mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 03:14:59 -06:00
1010 lines
28 KiB
C++
Executable File
1010 lines
28 KiB
C++
Executable File
// 7z/OutHandler.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "7zHandler.h"
|
|
#include "7zOut.h"
|
|
#include "7zUpdate.h"
|
|
|
|
#include "../../../Windows/PropVariant.h"
|
|
|
|
#include "../../../Common/ComTry.h"
|
|
#include "../../../Common/StringToInt.h"
|
|
#include "../../IPassword.h"
|
|
#include "../../ICoder.h"
|
|
|
|
#include "../Common/ItemNameUtils.h"
|
|
#include "../Common/ParseProperties.h"
|
|
|
|
using namespace NWindows;
|
|
|
|
namespace NArchive {
|
|
namespace N7z {
|
|
|
|
const wchar_t *kCopyMethod = L"Copy";
|
|
const wchar_t *kLZMAMethodName = L"LZMA";
|
|
const wchar_t *kLZMA2MethodName = L"LZMA2";
|
|
const wchar_t *kBZip2MethodName = L"BZip2";
|
|
const wchar_t *kPpmdMethodName = L"PPMd";
|
|
const wchar_t *kDeflateMethodName = L"Deflate";
|
|
const wchar_t *kDeflate64MethodName = L"Deflate64";
|
|
|
|
static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
|
|
static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
|
|
|
|
static const UInt32 kLzmaAlgorithmX1 = 0;
|
|
static const UInt32 kLzmaAlgorithmX5 = 1;
|
|
|
|
static const UInt32 kLzmaDicSizeX1 = 1 << 16;
|
|
static const UInt32 kLzmaDicSizeX3 = 1 << 20;
|
|
static const UInt32 kLzmaDicSizeX5 = 1 << 24;
|
|
static const UInt32 kLzmaDicSizeX7 = 1 << 25;
|
|
static const UInt32 kLzmaDicSizeX9 = 1 << 26;
|
|
|
|
static const UInt32 kLzmaFastBytesX1 = 32;
|
|
static const UInt32 kLzmaFastBytesX7 = 64;
|
|
|
|
static const UInt32 kPpmdMemSizeX1 = (1 << 22);
|
|
static const UInt32 kPpmdMemSizeX5 = (1 << 24);
|
|
static const UInt32 kPpmdMemSizeX7 = (1 << 26);
|
|
static const UInt32 kPpmdMemSizeX9 = (192 << 20);
|
|
|
|
static const UInt32 kPpmdOrderX1 = 4;
|
|
static const UInt32 kPpmdOrderX5 = 6;
|
|
static const UInt32 kPpmdOrderX7 = 16;
|
|
static const UInt32 kPpmdOrderX9 = 32;
|
|
|
|
static const UInt32 kDeflateFastBytesX1 = 32;
|
|
static const UInt32 kDeflateFastBytesX7 = 64;
|
|
static const UInt32 kDeflateFastBytesX9 = 128;
|
|
|
|
static const UInt32 kDeflatePassesX1 = 1;
|
|
static const UInt32 kDeflatePassesX7 = 3;
|
|
static const UInt32 kDeflatePassesX9 = 10;
|
|
|
|
static const UInt32 kBZip2NumPassesX1 = 1;
|
|
static const UInt32 kBZip2NumPassesX7 = 2;
|
|
static const UInt32 kBZip2NumPassesX9 = 7;
|
|
|
|
static const UInt32 kBZip2DicSizeX1 = 100000;
|
|
static const UInt32 kBZip2DicSizeX3 = 500000;
|
|
static const UInt32 kBZip2DicSizeX5 = 900000;
|
|
|
|
const wchar_t *kDefaultMethodName = kLZMAMethodName;
|
|
|
|
static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
|
|
static const UInt32 kDictionaryForHeaders = 1 << 20;
|
|
static const UInt32 kNumFastBytesForHeaders = 273;
|
|
static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5;
|
|
|
|
static bool IsCopyMethod(const UString &methodName)
|
|
{ return (methodName.CompareNoCase(kCopyMethod) == 0); }
|
|
|
|
static bool IsLZMAMethod(const UString &methodName)
|
|
{
|
|
return
|
|
(methodName.CompareNoCase(kLZMAMethodName) == 0) ||
|
|
(methodName.CompareNoCase(kLZMA2MethodName) == 0);
|
|
}
|
|
|
|
/*
|
|
static bool IsLZMethod(const UString &methodName)
|
|
{ return IsLZMAMethod(methodName); }
|
|
*/
|
|
|
|
static bool IsBZip2Method(const UString &methodName)
|
|
{ return (methodName.CompareNoCase(kBZip2MethodName) == 0); }
|
|
|
|
static bool IsPpmdMethod(const UString &methodName)
|
|
{ return (methodName.CompareNoCase(kPpmdMethodName) == 0); }
|
|
|
|
static bool IsDeflateMethod(const UString &methodName)
|
|
{ return (methodName.CompareNoCase(kDeflateMethodName) == 0) ||
|
|
(methodName.CompareNoCase(kDeflate64MethodName) == 0); }
|
|
|
|
STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
|
|
{
|
|
*type = NFileTimeType::kWindows;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CHandler::SetPassword(CCompressionMethodMode &methodMode,
|
|
IArchiveUpdateCallback *updateCallback)
|
|
{
|
|
CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
|
|
if (!getTextPassword)
|
|
{
|
|
CMyComPtr<IArchiveUpdateCallback> udateCallback2(updateCallback);
|
|
udateCallback2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
|
|
}
|
|
|
|
if (getTextPassword)
|
|
{
|
|
CMyComBSTR password;
|
|
Int32 passwordIsDefined;
|
|
RINOK(getTextPassword->CryptoGetTextPassword2(
|
|
&passwordIsDefined, &password));
|
|
methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
|
|
if (methodMode.PasswordIsDefined)
|
|
methodMode.Password = password;
|
|
}
|
|
else
|
|
methodMode.PasswordIsDefined = false;
|
|
return S_OK;
|
|
}
|
|
|
|
struct CNameToPropID
|
|
{
|
|
PROPID PropID;
|
|
VARTYPE VarType;
|
|
const wchar_t *Name;
|
|
};
|
|
|
|
CNameToPropID g_NameToPropID[] =
|
|
{
|
|
{ NCoderPropID::kOrder, VT_UI4, L"O" },
|
|
{ NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
|
|
{ NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
|
|
{ NCoderPropID::kLitPosBits, VT_UI4, L"LP" },
|
|
|
|
{ NCoderPropID::kNumPasses, VT_UI4, L"Pass" },
|
|
{ NCoderPropID::kNumFastBytes, VT_UI4, L"fb" },
|
|
{ NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
|
|
{ NCoderPropID::kAlgorithm, VT_UI4, L"a" },
|
|
{ NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
|
|
{ NCoderPropID::kNumThreads, VT_UI4, L"mt" }
|
|
};
|
|
|
|
bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType,
|
|
NCOM::CPropVariant &destProp)
|
|
{
|
|
if (varType == srcProp.vt)
|
|
{
|
|
destProp = srcProp;
|
|
return true;
|
|
}
|
|
if (varType == VT_UI1)
|
|
{
|
|
if(srcProp.vt == VT_UI4)
|
|
{
|
|
UInt32 value = srcProp.ulVal;
|
|
if (value > 0xFF)
|
|
return false;
|
|
destProp = Byte(value);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const int kNumNameToPropIDItems = sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]);
|
|
|
|
int FindPropIdFromStringName(const UString &name)
|
|
{
|
|
for (int i = 0; i < kNumNameToPropIDItems; i++)
|
|
if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
HRESULT CHandler::SetCompressionMethod(
|
|
CCompressionMethodMode &methodMode,
|
|
CCompressionMethodMode &headerMethod)
|
|
{
|
|
HRESULT res = SetCompressionMethod(methodMode, _methods
|
|
#ifdef COMPRESS_MT
|
|
, _numThreads
|
|
#endif
|
|
);
|
|
RINOK(res);
|
|
methodMode.Binds = _binds;
|
|
|
|
if (_compressHeaders)
|
|
{
|
|
// headerMethod.Methods.Add(methodMode.Methods.Back());
|
|
|
|
CObjectVector<COneMethodInfo> headerMethodInfoVector;
|
|
COneMethodInfo oneMethodInfo;
|
|
oneMethodInfo.MethodName = kLZMAMethodName;
|
|
{
|
|
CProperty property;
|
|
property.PropID = NCoderPropID::kMatchFinder;
|
|
property.Value = kLzmaMatchFinderForHeaders;
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
}
|
|
{
|
|
CProperty property;
|
|
property.PropID = NCoderPropID::kAlgorithm;
|
|
property.Value = kAlgorithmForHeaders;
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
}
|
|
{
|
|
CProperty property;
|
|
property.PropID = NCoderPropID::kNumFastBytes;
|
|
property.Value = UInt32(kNumFastBytesForHeaders);
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
}
|
|
{
|
|
CProperty property;
|
|
property.PropID = NCoderPropID::kDictionarySize;
|
|
property.Value = UInt32(kDictionaryForHeaders);
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
}
|
|
headerMethodInfoVector.Add(oneMethodInfo);
|
|
HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector
|
|
#ifdef COMPRESS_MT
|
|
,1
|
|
#endif
|
|
);
|
|
RINOK(res);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static void SetOneMethodProp(COneMethodInfo &oneMethodInfo, PROPID propID,
|
|
const NWindows::NCOM::CPropVariant &value)
|
|
{
|
|
int j;
|
|
for (j = 0; j < oneMethodInfo.CoderProperties.Size(); j++)
|
|
if (oneMethodInfo.CoderProperties[j].PropID == propID)
|
|
break;
|
|
if (j != oneMethodInfo.CoderProperties.Size())
|
|
return;
|
|
CProperty property;
|
|
property.PropID = propID;
|
|
property.Value = value;
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
}
|
|
|
|
HRESULT CHandler::SetCompressionMethod(
|
|
CCompressionMethodMode &methodMode,
|
|
CObjectVector<COneMethodInfo> &methodsInfo
|
|
#ifdef COMPRESS_MT
|
|
, UInt32 numThreads
|
|
#endif
|
|
)
|
|
{
|
|
UInt32 level = _level;
|
|
|
|
if (methodsInfo.IsEmpty())
|
|
{
|
|
COneMethodInfo oneMethodInfo;
|
|
oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName);
|
|
methodsInfo.Add(oneMethodInfo);
|
|
}
|
|
|
|
bool needSolid = false;
|
|
for(int i = 0; i < methodsInfo.Size(); i++)
|
|
{
|
|
COneMethodInfo &oneMethodInfo = methodsInfo[i];
|
|
if (oneMethodInfo.MethodName.IsEmpty())
|
|
oneMethodInfo.MethodName = kDefaultMethodName;
|
|
|
|
if (!IsCopyMethod(oneMethodInfo.MethodName))
|
|
needSolid = true;
|
|
|
|
if (IsLZMAMethod(oneMethodInfo.MethodName))
|
|
{
|
|
UInt32 dicSize =
|
|
(level >= 9 ? kLzmaDicSizeX9 :
|
|
(level >= 7 ? kLzmaDicSizeX7 :
|
|
(level >= 5 ? kLzmaDicSizeX5 :
|
|
(level >= 3 ? kLzmaDicSizeX3 :
|
|
kLzmaDicSizeX1))));
|
|
|
|
UInt32 algorithm =
|
|
(level >= 5 ? kLzmaAlgorithmX5 :
|
|
kLzmaAlgorithmX1);
|
|
|
|
UInt32 fastBytes =
|
|
(level >= 7 ? kLzmaFastBytesX7 :
|
|
kLzmaFastBytesX1);
|
|
|
|
const wchar_t *matchFinder =
|
|
(level >= 5 ? kLzmaMatchFinderX5 :
|
|
kLzmaMatchFinderX1);
|
|
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algorithm);
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
|
|
#ifdef COMPRESS_MT
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
|
|
#endif
|
|
}
|
|
else if (IsDeflateMethod(oneMethodInfo.MethodName))
|
|
{
|
|
UInt32 fastBytes =
|
|
(level >= 9 ? kDeflateFastBytesX9 :
|
|
(level >= 7 ? kDeflateFastBytesX7 :
|
|
kDeflateFastBytesX1));
|
|
|
|
UInt32 numPasses =
|
|
(level >= 9 ? kDeflatePassesX9 :
|
|
(level >= 7 ? kDeflatePassesX7 :
|
|
kDeflatePassesX1));
|
|
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
|
|
}
|
|
else if (IsBZip2Method(oneMethodInfo.MethodName))
|
|
{
|
|
UInt32 numPasses =
|
|
(level >= 9 ? kBZip2NumPassesX9 :
|
|
(level >= 7 ? kBZip2NumPassesX7 :
|
|
kBZip2NumPassesX1));
|
|
|
|
UInt32 dicSize =
|
|
(level >= 5 ? kBZip2DicSizeX5 :
|
|
(level >= 3 ? kBZip2DicSizeX3 :
|
|
kBZip2DicSizeX1));
|
|
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
|
|
#ifdef COMPRESS_MT
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
|
|
#endif
|
|
}
|
|
else if (IsPpmdMethod(oneMethodInfo.MethodName))
|
|
{
|
|
UInt32 useMemSize =
|
|
(level >= 9 ? kPpmdMemSizeX9 :
|
|
(level >= 7 ? kPpmdMemSizeX7 :
|
|
(level >= 5 ? kPpmdMemSizeX5 :
|
|
kPpmdMemSizeX1)));
|
|
|
|
UInt32 order =
|
|
(level >= 9 ? kPpmdOrderX9 :
|
|
(level >= 7 ? kPpmdOrderX7 :
|
|
(level >= 5 ? kPpmdOrderX5 :
|
|
kPpmdOrderX1)));
|
|
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
|
|
SetOneMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
|
|
}
|
|
|
|
|
|
CMethodFull methodFull;
|
|
|
|
if (!FindMethod(
|
|
EXTERNAL_CODECS_VARS
|
|
oneMethodInfo.MethodName, methodFull.MethodID, methodFull.NumInStreams, methodFull.NumOutStreams))
|
|
return E_INVALIDARG;
|
|
methodFull.CoderProperties = oneMethodInfo.CoderProperties;
|
|
methodMode.Methods.Add(methodFull);
|
|
|
|
if (!_numSolidBytesDefined)
|
|
{
|
|
for (int j = 0; j < methodFull.CoderProperties.Size(); j++)
|
|
{
|
|
const CProperty &prop = methodFull.CoderProperties[j];
|
|
if ((prop.PropID == NCoderPropID::kDictionarySize ||
|
|
prop.PropID == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4)
|
|
{
|
|
_numSolidBytes = ((UInt64)prop.Value.ulVal) << 7;
|
|
const UInt64 kMinSize = (1 << 24);
|
|
if (_numSolidBytes < kMinSize)
|
|
_numSolidBytes = kMinSize;
|
|
_numSolidBytesDefined = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!needSolid && !_numSolidBytesDefined)
|
|
{
|
|
_numSolidBytesDefined = true;
|
|
_numSolidBytes = 0;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, CArchiveFileTime &filetime, bool &filetimeIsDefined)
|
|
{
|
|
filetimeIsDefined = false;
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(index, propID, &propVariant));
|
|
if (propVariant.vt == VT_FILETIME)
|
|
{
|
|
filetime = propVariant.filetime;
|
|
filetimeIsDefined = true;
|
|
}
|
|
else if (propVariant.vt != VT_EMPTY)
|
|
return E_INVALIDARG;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
|
|
IArchiveUpdateCallback *updateCallback)
|
|
{
|
|
COM_TRY_BEGIN
|
|
|
|
const CArchiveDatabaseEx *database = 0;
|
|
#ifdef _7Z_VOL
|
|
if(_volumes.Size() > 1)
|
|
return E_FAIL;
|
|
const CVolume *volume = 0;
|
|
if (_volumes.Size() == 1)
|
|
{
|
|
volume = &_volumes.Front();
|
|
database = &volume->Database;
|
|
}
|
|
#else
|
|
if (_inStream != 0)
|
|
database = &_database;
|
|
#endif
|
|
|
|
// CRecordVector<bool> compressStatuses;
|
|
CObjectVector<CUpdateItem> updateItems;
|
|
// CRecordVector<UInt32> copyIndices;
|
|
|
|
// CMyComPtr<IUpdateCallback2> updateCallback2;
|
|
// updateCallback->QueryInterface(&updateCallback2);
|
|
|
|
for(UInt32 i = 0; i < numItems; i++)
|
|
{
|
|
Int32 newData;
|
|
Int32 newProperties;
|
|
UInt32 indexInArchive;
|
|
if (!updateCallback)
|
|
return E_FAIL;
|
|
RINOK(updateCallback->GetUpdateItemInfo(i,
|
|
&newData, &newProperties, &indexInArchive));
|
|
CUpdateItem updateItem;
|
|
updateItem.NewProperties = IntToBool(newProperties);
|
|
updateItem.NewData = IntToBool(newData);
|
|
updateItem.IndexInArchive = indexInArchive;
|
|
updateItem.IndexInClient = i;
|
|
updateItem.IsAnti = false;
|
|
updateItem.Size = 0;
|
|
|
|
if (updateItem.IndexInArchive != -1)
|
|
{
|
|
const CFileItem &fileItem = database->Files[updateItem.IndexInArchive];
|
|
updateItem.Name = fileItem.Name;
|
|
updateItem.IsDirectory = fileItem.IsDirectory;
|
|
updateItem.Size = fileItem.UnPackSize;
|
|
updateItem.IsAnti = fileItem.IsAnti;
|
|
|
|
updateItem.CreationTime = fileItem.CreationTime;
|
|
updateItem.IsCreationTimeDefined = fileItem.IsCreationTimeDefined;
|
|
updateItem.LastWriteTime = fileItem.LastWriteTime;
|
|
updateItem.IsLastWriteTimeDefined = fileItem.IsLastWriteTimeDefined;
|
|
updateItem.LastAccessTime = fileItem.LastAccessTime;
|
|
updateItem.IsLastAccessTimeDefined = fileItem.IsLastAccessTimeDefined;
|
|
}
|
|
|
|
if (updateItem.NewProperties)
|
|
{
|
|
bool nameIsDefined;
|
|
bool folderStatusIsDefined;
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(i, kpidAttributes, &propVariant));
|
|
if (propVariant.vt == VT_EMPTY)
|
|
updateItem.AttributesAreDefined = false;
|
|
else if (propVariant.vt != VT_UI4)
|
|
return E_INVALIDARG;
|
|
else
|
|
{
|
|
updateItem.Attributes = propVariant.ulVal;
|
|
updateItem.AttributesAreDefined = true;
|
|
}
|
|
}
|
|
|
|
RINOK(GetTime(updateCallback, i, kpidCreationTime, updateItem.CreationTime, updateItem.IsCreationTimeDefined));
|
|
RINOK(GetTime(updateCallback, i, kpidLastWriteTime, updateItem.LastWriteTime , updateItem.IsLastWriteTimeDefined));
|
|
RINOK(GetTime(updateCallback, i, kpidLastAccessTime, updateItem.LastAccessTime, updateItem.IsLastAccessTimeDefined));
|
|
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(i, kpidPath, &propVariant));
|
|
if (propVariant.vt == VT_EMPTY)
|
|
nameIsDefined = false;
|
|
else if (propVariant.vt != VT_BSTR)
|
|
return E_INVALIDARG;
|
|
else
|
|
{
|
|
updateItem.Name = NItemName::MakeLegalName(propVariant.bstrVal);
|
|
nameIsDefined = true;
|
|
}
|
|
}
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(i, kpidIsFolder, &propVariant));
|
|
if (propVariant.vt == VT_EMPTY)
|
|
folderStatusIsDefined = false;
|
|
else if (propVariant.vt != VT_BOOL)
|
|
return E_INVALIDARG;
|
|
else
|
|
{
|
|
updateItem.IsDirectory = (propVariant.boolVal != VARIANT_FALSE);
|
|
folderStatusIsDefined = true;
|
|
}
|
|
}
|
|
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(i, kpidIsAnti, &propVariant));
|
|
if (propVariant.vt == VT_EMPTY)
|
|
updateItem.IsAnti = false;
|
|
else if (propVariant.vt != VT_BOOL)
|
|
return E_INVALIDARG;
|
|
else
|
|
updateItem.IsAnti = (propVariant.boolVal != VARIANT_FALSE);
|
|
}
|
|
|
|
if (updateItem.IsAnti)
|
|
{
|
|
updateItem.AttributesAreDefined = false;
|
|
|
|
updateItem.IsCreationTimeDefined = false;
|
|
updateItem.IsLastWriteTimeDefined = false;
|
|
updateItem.IsLastAccessTimeDefined = false;
|
|
|
|
updateItem.Size = 0;
|
|
}
|
|
|
|
if (!folderStatusIsDefined && updateItem.AttributesAreDefined)
|
|
updateItem.SetDirectoryStatusFromAttributes();
|
|
}
|
|
|
|
if (updateItem.NewData)
|
|
{
|
|
NCOM::CPropVariant propVariant;
|
|
RINOK(updateCallback->GetProperty(i, kpidSize, &propVariant));
|
|
if (propVariant.vt != VT_UI8)
|
|
return E_INVALIDARG;
|
|
updateItem.Size = (UInt64)propVariant.uhVal.QuadPart;
|
|
if (updateItem.Size != 0 && updateItem.IsAnti)
|
|
return E_INVALIDARG;
|
|
}
|
|
updateItems.Add(updateItem);
|
|
}
|
|
|
|
CCompressionMethodMode methodMode, headerMethod;
|
|
RINOK(SetCompressionMethod(methodMode, headerMethod));
|
|
#ifdef COMPRESS_MT
|
|
methodMode.NumThreads = _numThreads;
|
|
headerMethod.NumThreads = 1;
|
|
#endif
|
|
|
|
RINOK(SetPassword(methodMode, updateCallback));
|
|
|
|
bool compressMainHeader = _compressHeaders; // check it
|
|
|
|
if (methodMode.PasswordIsDefined)
|
|
{
|
|
compressMainHeader = true;
|
|
if(_encryptHeaders)
|
|
RINOK(SetPassword(headerMethod, updateCallback));
|
|
}
|
|
|
|
if (numItems < 2)
|
|
compressMainHeader = false;
|
|
|
|
CUpdateOptions options;
|
|
options.Method = &methodMode;
|
|
options.HeaderMethod = (_compressHeaders ||
|
|
(methodMode.PasswordIsDefined && _encryptHeaders)) ?
|
|
&headerMethod : 0;
|
|
options.UseFilters = _level != 0 && _autoFilter;
|
|
options.MaxFilter = _level >= 8;
|
|
|
|
options.HeaderOptions.CompressMainHeader = compressMainHeader;
|
|
options.HeaderOptions.WriteModified = WriteModified;
|
|
options.HeaderOptions.WriteCreated = WriteCreated;
|
|
options.HeaderOptions.WriteAccessed = WriteAccessed;
|
|
|
|
options.NumSolidFiles = _numSolidFiles;
|
|
options.NumSolidBytes = _numSolidBytes;
|
|
options.SolidExtension = _solidExtension;
|
|
options.RemoveSfxBlock = _removeSfxBlock;
|
|
options.VolumeMode = _volumeMode;
|
|
return Update(
|
|
EXTERNAL_CODECS_VARS
|
|
#ifdef _7Z_VOL
|
|
volume ? volume->Stream: 0,
|
|
volume ? database: 0,
|
|
#else
|
|
_inStream,
|
|
database,
|
|
#endif
|
|
updateItems, outStream, updateCallback, options);
|
|
COM_TRY_END
|
|
}
|
|
|
|
static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
|
|
{
|
|
stream = 0;
|
|
int index = ParseStringToUInt32(srcString, coder);
|
|
if (index == 0)
|
|
return E_INVALIDARG;
|
|
srcString.Delete(0, index);
|
|
if (srcString[0] == 'S')
|
|
{
|
|
srcString.Delete(0);
|
|
int index = ParseStringToUInt32(srcString, stream);
|
|
if (index == 0)
|
|
return E_INVALIDARG;
|
|
srcString.Delete(0, index);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT GetBindInfo(UString &srcString, CBind &bind)
|
|
{
|
|
RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream));
|
|
if (srcString[0] != ':')
|
|
return E_INVALIDARG;
|
|
srcString.Delete(0);
|
|
RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream));
|
|
if (!srcString.IsEmpty())
|
|
return E_INVALIDARG;
|
|
return S_OK;
|
|
}
|
|
|
|
static void SplitParams(const UString &srcString, UStringVector &subStrings)
|
|
{
|
|
subStrings.Clear();
|
|
UString name;
|
|
int len = srcString.Length();
|
|
if (len == 0)
|
|
return;
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
wchar_t c = srcString[i];
|
|
if (c == L':')
|
|
{
|
|
subStrings.Add(name);
|
|
name.Empty();
|
|
}
|
|
else
|
|
name += c;
|
|
}
|
|
subStrings.Add(name);
|
|
}
|
|
|
|
static void SplitParam(const UString ¶m, UString &name, UString &value)
|
|
{
|
|
int eqPos = param.Find(L'=');
|
|
if (eqPos >= 0)
|
|
{
|
|
name = param.Left(eqPos);
|
|
value = param.Mid(eqPos + 1);
|
|
return;
|
|
}
|
|
for(int i = 0; i < param.Length(); i++)
|
|
{
|
|
wchar_t c = param[i];
|
|
if (c >= L'0' && c <= L'9')
|
|
{
|
|
name = param.Left(i);
|
|
value = param.Mid(i);
|
|
return;
|
|
}
|
|
}
|
|
name = param;
|
|
}
|
|
|
|
HRESULT CHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value)
|
|
{
|
|
CProperty property;
|
|
if (name.CompareNoCase(L"D") == 0 || name.CompareNoCase(L"MEM") == 0)
|
|
{
|
|
UInt32 dicSize;
|
|
RINOK(ParsePropDictionaryValue(value, dicSize));
|
|
if (name.CompareNoCase(L"D") == 0)
|
|
property.PropID = NCoderPropID::kDictionarySize;
|
|
else
|
|
property.PropID = NCoderPropID::kUsedMemorySize;
|
|
property.Value = dicSize;
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
}
|
|
else
|
|
{
|
|
int index = FindPropIdFromStringName(name);
|
|
if (index < 0)
|
|
return E_INVALIDARG;
|
|
|
|
const CNameToPropID &nameToPropID = g_NameToPropID[index];
|
|
property.PropID = nameToPropID.PropID;
|
|
|
|
NCOM::CPropVariant propValue;
|
|
|
|
|
|
if (nameToPropID.VarType == VT_BSTR)
|
|
propValue = value;
|
|
else
|
|
{
|
|
UInt32 number;
|
|
if (ParseStringToUInt32(value, number) == value.Length())
|
|
propValue = number;
|
|
else
|
|
propValue = value;
|
|
}
|
|
|
|
if (!ConvertProperty(propValue, nameToPropID.VarType, property.Value))
|
|
return E_INVALIDARG;
|
|
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString)
|
|
{
|
|
UStringVector params;
|
|
SplitParams(srcString, params);
|
|
if (params.Size() > 0)
|
|
oneMethodInfo.MethodName = params[0];
|
|
for (int i = 1; i < params.Size(); i++)
|
|
{
|
|
const UString ¶m = params[i];
|
|
UString name, value;
|
|
SplitParam(param, name, value);
|
|
RINOK(SetParam(oneMethodInfo, name, value));
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CHandler::SetSolidSettings(const UString &s)
|
|
{
|
|
UString s2 = s;
|
|
s2.MakeUpper();
|
|
if (s2.IsEmpty() || s2.Compare(L"ON") == 0)
|
|
{
|
|
InitSolid();
|
|
return S_OK;
|
|
}
|
|
if (s2.Compare(L"OFF") == 0)
|
|
{
|
|
_numSolidFiles = 1;
|
|
return S_OK;
|
|
}
|
|
for (int i = 0; i < s2.Length();)
|
|
{
|
|
const wchar_t *start = ((const wchar_t *)s2) + i;
|
|
const wchar_t *end;
|
|
UInt64 v = ConvertStringToUInt64(start, &end);
|
|
if (start == end)
|
|
{
|
|
if (s2[i++] != 'E')
|
|
return E_INVALIDARG;
|
|
_solidExtension = true;
|
|
continue;
|
|
}
|
|
i += (int)(end - start);
|
|
if (i == s2.Length())
|
|
return E_INVALIDARG;
|
|
wchar_t c = s2[i++];
|
|
switch(c)
|
|
{
|
|
case 'F':
|
|
if (v < 1)
|
|
v = 1;
|
|
_numSolidFiles = v;
|
|
break;
|
|
case 'B':
|
|
_numSolidBytes = v;
|
|
_numSolidBytesDefined = true;
|
|
break;
|
|
case 'K':
|
|
_numSolidBytes = (v << 10);
|
|
_numSolidBytesDefined = true;
|
|
break;
|
|
case 'M':
|
|
_numSolidBytes = (v << 20);
|
|
_numSolidBytesDefined = true;
|
|
break;
|
|
case 'G':
|
|
_numSolidBytes = (v << 30);
|
|
_numSolidBytesDefined = true;
|
|
break;
|
|
default:
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CHandler::SetSolidSettings(const PROPVARIANT &value)
|
|
{
|
|
switch(value.vt)
|
|
{
|
|
case VT_EMPTY:
|
|
InitSolid();
|
|
return S_OK;
|
|
case VT_BSTR:
|
|
return SetSolidSettings(value.bstrVal);
|
|
default:
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
|
|
{
|
|
COM_TRY_BEGIN
|
|
_methods.Clear();
|
|
_binds.Clear();
|
|
Init();
|
|
#ifdef COMPRESS_MT
|
|
const UInt32 numProcessors = NSystem::GetNumberOfProcessors();
|
|
#endif
|
|
|
|
UInt32 mainDicSize = 0xFFFFFFFF;
|
|
UInt32 mainDicMethodIndex = 0xFFFFFFFF;
|
|
|
|
UInt32 minNumber = 0;
|
|
|
|
for (int i = 0; i < numProperties; i++)
|
|
{
|
|
UString name = names[i];
|
|
name.MakeUpper();
|
|
if (name.IsEmpty())
|
|
return E_INVALIDARG;
|
|
|
|
const PROPVARIANT &value = values[i];
|
|
|
|
if (name[0] == 'X')
|
|
{
|
|
name.Delete(0);
|
|
_level = 9;
|
|
RINOK(ParsePropValue(name, value, _level));
|
|
continue;
|
|
}
|
|
|
|
if (name[0] == 'B')
|
|
{
|
|
name.Delete(0);
|
|
CBind bind;
|
|
RINOK(GetBindInfo(name, bind));
|
|
_binds.Add(bind);
|
|
continue;
|
|
}
|
|
|
|
if (name[0] == L'S')
|
|
{
|
|
name.Delete(0);
|
|
if (name.IsEmpty())
|
|
{
|
|
RINOK(SetSolidSettings(value));
|
|
}
|
|
else
|
|
{
|
|
RINOK(SetSolidSettings(name));
|
|
}
|
|
continue;
|
|
}
|
|
|
|
|
|
UInt32 number;
|
|
int index = ParseStringToUInt32(name, number);
|
|
UString realName = name.Mid(index);
|
|
if (index == 0)
|
|
{
|
|
if(name.Left(2).CompareNoCase(L"MT") == 0)
|
|
{
|
|
#ifdef COMPRESS_MT
|
|
RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
|
|
#endif
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"RSFX") == 0)
|
|
{
|
|
RINOK(SetBoolProperty(_removeSfxBlock, value));
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"F") == 0)
|
|
{
|
|
RINOK(SetBoolProperty(_autoFilter, value));
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"HC") == 0)
|
|
{
|
|
RINOK(SetBoolProperty(_compressHeaders, value));
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"HCF") == 0)
|
|
{
|
|
bool compressHeadersFull = true;
|
|
RINOK(SetBoolProperty(compressHeadersFull, value));
|
|
if (!compressHeadersFull)
|
|
return E_INVALIDARG;
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"HE") == 0)
|
|
{
|
|
RINOK(SetBoolProperty(_encryptHeaders, value));
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"TM") == 0)
|
|
{
|
|
RINOK(SetBoolProperty(WriteModified, value));
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"TC") == 0)
|
|
{
|
|
RINOK(SetBoolProperty(WriteCreated, value));
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"TA") == 0)
|
|
{
|
|
RINOK(SetBoolProperty(WriteAccessed, value));
|
|
continue;
|
|
}
|
|
else if (name.CompareNoCase(L"V") == 0)
|
|
{
|
|
RINOK(SetBoolProperty(_volumeMode, value));
|
|
continue;
|
|
}
|
|
number = 0;
|
|
}
|
|
if (number > 10000)
|
|
return E_FAIL;
|
|
if (number < minNumber)
|
|
return E_INVALIDARG;
|
|
number -= minNumber;
|
|
for(int j = _methods.Size(); j <= (int)number; j++)
|
|
{
|
|
COneMethodInfo oneMethodInfo;
|
|
_methods.Add(oneMethodInfo);
|
|
}
|
|
|
|
COneMethodInfo &oneMethodInfo = _methods[number];
|
|
|
|
if (realName.Length() == 0)
|
|
{
|
|
if (value.vt != VT_BSTR)
|
|
return E_INVALIDARG;
|
|
|
|
// oneMethodInfo.MethodName = UnicodeStringToMultiByte(UString(value.bstrVal));
|
|
RINOK(SetParams(oneMethodInfo, value.bstrVal));
|
|
}
|
|
else
|
|
{
|
|
CProperty property;
|
|
if (realName.Left(1).CompareNoCase(L"D") == 0)
|
|
{
|
|
UInt32 dicSize;
|
|
RINOK(ParsePropDictionaryValue(realName.Mid(1), value, dicSize));
|
|
property.PropID = NCoderPropID::kDictionarySize;
|
|
property.Value = dicSize;
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
if (number <= mainDicMethodIndex)
|
|
mainDicSize = dicSize;
|
|
}
|
|
else if (realName.Left(3).CompareNoCase(L"MEM") == 0)
|
|
{
|
|
UInt32 dicSize;
|
|
RINOK(ParsePropDictionaryValue(realName.Mid(3), value, dicSize));
|
|
property.PropID = NCoderPropID::kUsedMemorySize;
|
|
property.Value = dicSize;
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
if (number <= mainDicMethodIndex)
|
|
mainDicSize = dicSize;
|
|
}
|
|
else
|
|
{
|
|
int index = FindPropIdFromStringName(realName);
|
|
if (index < 0)
|
|
return E_INVALIDARG;
|
|
|
|
const CNameToPropID &nameToPropID = g_NameToPropID[index];
|
|
property.PropID = nameToPropID.PropID;
|
|
|
|
if (!ConvertProperty(value, nameToPropID.VarType, property.Value))
|
|
return E_INVALIDARG;
|
|
|
|
oneMethodInfo.CoderProperties.Add(property);
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
COM_TRY_END
|
|
}
|
|
|
|
}}
|