// HandlerOut.cpp | |
#include "StdAfx.h" | |
#include "../../../Common/StringToInt.h" | |
#include "../../../Windows/PropVariant.h" | |
#ifndef _7ZIP_ST | |
#include "../../../Windows/System.h" | |
#endif | |
#include "../../ICoder.h" | |
#include "../Common/ParseProperties.h" | |
#include "HandlerOut.h" | |
using namespace NWindows; | |
namespace NArchive { | |
static const wchar_t *kCopyMethod = L"Copy"; | |
static const wchar_t *kLZMAMethodName = L"LZMA"; | |
static const wchar_t *kLZMA2MethodName = L"LZMA2"; | |
static const wchar_t *kBZip2MethodName = L"BZip2"; | |
static const wchar_t *kPpmdMethodName = L"PPMd"; | |
static const wchar_t *kDeflateMethodName = L"Deflate"; | |
static const wchar_t *kDeflate64MethodName = L"Deflate64"; | |
static const wchar_t *kLzmaMatchFinderX1 = L"HC4"; | |
static const wchar_t *kLzmaMatchFinderX5 = L"BT4"; | |
static const UInt32 kLzmaAlgoX1 = 0; | |
static const UInt32 kLzmaAlgoX5 = 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 kDeflateAlgoX1 = 0; | |
static const UInt32 kDeflateAlgoX5 = 1; | |
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; | |
static 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 = kLzmaAlgoX5; | |
static bool AreEqual(const UString &methodName, const wchar_t *s) | |
{ return (methodName.CompareNoCase(s) == 0); } | |
bool COneMethodInfo::IsLzma() const | |
{ | |
return | |
AreEqual(MethodName, kLZMAMethodName) || | |
AreEqual(MethodName, kLZMA2MethodName); | |
} | |
static inline bool IsBZip2Method(const UString &methodName) | |
{ return AreEqual(methodName, kBZip2MethodName); } | |
static inline bool IsPpmdMethod(const UString &methodName) | |
{ return AreEqual(methodName, kPpmdMethodName); } | |
static inline bool IsDeflateMethod(const UString &methodName) | |
{ | |
return | |
AreEqual(methodName, kDeflateMethodName) || | |
AreEqual(methodName, kDeflate64MethodName); | |
} | |
struct CNameToPropID | |
{ | |
PROPID PropID; | |
VARTYPE VarType; | |
const wchar_t *Name; | |
}; | |
static CNameToPropID g_NameToPropID[] = | |
{ | |
{ NCoderPropID::kBlockSize, VT_UI4, L"C" }, | |
{ NCoderPropID::kDictionarySize, VT_UI4, L"D" }, | |
{ NCoderPropID::kUsedMemorySize, VT_UI4, L"MEM" }, | |
{ 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::kEndMarker, VT_BOOL, L"eos" }, | |
{ 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" }, | |
{ NCoderPropID::kDefaultProp, VT_UI4, L"" } | |
}; | |
static 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; | |
} | |
} | |
else if (varType == VT_BOOL) | |
{ | |
bool res; | |
if (SetBoolProperty(res, srcProp) != S_OK) | |
return false; | |
destProp = res; | |
return true; | |
} | |
return false; | |
} | |
static int FindPropIdExact(const UString &name) | |
{ | |
for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++) | |
if (name.CompareNoCase(g_NameToPropID[i].Name) == 0) | |
return i; | |
return -1; | |
} | |
static int FindPropIdStart(const UString &name) | |
{ | |
for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++) | |
{ | |
UString t = g_NameToPropID[i].Name; | |
if (t.CompareNoCase(name.Left(t.Length())) == 0) | |
return i; | |
} | |
return -1; | |
} | |
static void SetMethodProp(COneMethodInfo &m, PROPID propID, const NCOM::CPropVariant &value) | |
{ | |
for (int j = 0; j < m.Props.Size(); j++) | |
if (m.Props[j].Id == propID) | |
return; | |
CProp prop; | |
prop.Id = propID; | |
prop.Value = value; | |
m.Props.Add(prop); | |
} | |
void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo | |
#ifndef _7ZIP_ST | |
, UInt32 numThreads | |
#endif | |
) | |
{ | |
UInt32 level = _level; | |
if (oneMethodInfo.MethodName.IsEmpty()) | |
oneMethodInfo.MethodName = kDefaultMethodName; | |
if (oneMethodInfo.IsLzma()) | |
{ | |
UInt32 dicSize = | |
(level >= 9 ? kLzmaDicSizeX9 : | |
(level >= 7 ? kLzmaDicSizeX7 : | |
(level >= 5 ? kLzmaDicSizeX5 : | |
(level >= 3 ? kLzmaDicSizeX3 : | |
kLzmaDicSizeX1)))); | |
UInt32 algo = | |
(level >= 5 ? kLzmaAlgoX5 : | |
kLzmaAlgoX1); | |
UInt32 fastBytes = | |
(level >= 7 ? kLzmaFastBytesX7 : | |
kLzmaFastBytesX1); | |
const wchar_t *matchFinder = | |
(level >= 5 ? kLzmaMatchFinderX5 : | |
kLzmaMatchFinderX1); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder); | |
#ifndef _7ZIP_ST | |
SetMethodProp(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)); | |
UInt32 algo = | |
(level >= 5 ? kDeflateAlgoX5 : | |
kDeflateAlgoX1); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes); | |
SetMethodProp(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)); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize); | |
#ifndef _7ZIP_ST | |
SetMethodProp(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))); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize); | |
SetMethodProp(oneMethodInfo, NCoderPropID::kOrder, order); | |
} | |
} | |
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 COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value) | |
{ | |
CProp prop; | |
int index = FindPropIdExact(name); | |
if (index < 0) | |
return E_INVALIDARG; | |
const CNameToPropID &nameToPropID = g_NameToPropID[index]; | |
prop.Id = nameToPropID.PropID; | |
if (prop.Id == NCoderPropID::kBlockSize || | |
prop.Id == NCoderPropID::kDictionarySize || | |
prop.Id == NCoderPropID::kUsedMemorySize) | |
{ | |
UInt32 dicSize; | |
RINOK(ParsePropDictionaryValue(value, dicSize)); | |
prop.Value = dicSize; | |
} | |
else | |
{ | |
NCOM::CPropVariant propValue; | |
if (nameToPropID.VarType == VT_BSTR) | |
propValue = value; | |
else if (nameToPropID.VarType == VT_BOOL) | |
{ | |
bool res; | |
if (!StringToBool(value, res)) | |
return E_INVALIDARG; | |
propValue = res; | |
} | |
else | |
{ | |
UInt32 number; | |
if (ParseStringToUInt32(value, number) == value.Length()) | |
propValue = number; | |
else | |
propValue = value; | |
} | |
if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) | |
return E_INVALIDARG; | |
} | |
oneMethodInfo.Props.Add(prop); | |
return S_OK; | |
} | |
HRESULT COutHandler::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 COutHandler::SetSolidSettings(const UString &s) | |
{ | |
UString s2 = s; | |
s2.MakeUpper(); | |
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 COutHandler::SetSolidSettings(const PROPVARIANT &value) | |
{ | |
bool isSolid; | |
switch(value.vt) | |
{ | |
case VT_EMPTY: | |
isSolid = true; | |
break; | |
case VT_BOOL: | |
isSolid = (value.boolVal != VARIANT_FALSE); | |
break; | |
case VT_BSTR: | |
if (StringToBool(value.bstrVal, isSolid)) | |
break; | |
return SetSolidSettings(value.bstrVal); | |
default: | |
return E_INVALIDARG; | |
} | |
if (isSolid) | |
InitSolid(); | |
else | |
_numSolidFiles = 1; | |
return S_OK; | |
} | |
void COutHandler::Init() | |
{ | |
_removeSfxBlock = false; | |
_compressHeaders = true; | |
_encryptHeadersSpecified = false; | |
_encryptHeaders = false; | |
WriteCTime = false; | |
WriteATime = false; | |
WriteMTime = true; | |
#ifndef _7ZIP_ST | |
_numThreads = NSystem::GetNumberOfProcessors(); | |
#endif | |
_level = 5; | |
_autoFilter = true; | |
_volumeMode = false; | |
_crcSize = 4; | |
InitSolid(); | |
} | |
void COutHandler::BeforeSetProperty() | |
{ | |
Init(); | |
#ifndef _7ZIP_ST | |
numProcessors = NSystem::GetNumberOfProcessors(); | |
#endif | |
mainDicSize = 0xFFFFFFFF; | |
mainDicMethodIndex = 0xFFFFFFFF; | |
minNumber = 0; | |
_crcSize = 4; | |
} | |
HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) | |
{ | |
UString name = nameSpec; | |
name.MakeUpper(); | |
if (name.IsEmpty()) | |
return E_INVALIDARG; | |
if (name[0] == 'X') | |
{ | |
name.Delete(0); | |
_level = 9; | |
return ParsePropValue(name, value, _level); | |
} | |
if (name[0] == L'S') | |
{ | |
name.Delete(0); | |
if (name.IsEmpty()) | |
return SetSolidSettings(value); | |
if (value.vt != VT_EMPTY) | |
return E_INVALIDARG; | |
return SetSolidSettings(name); | |
} | |
if (name == L"CRC") | |
{ | |
_crcSize = 4; | |
name.Delete(0, 3); | |
return ParsePropValue(name, value, _crcSize); | |
} | |
UInt32 number; | |
int index = ParseStringToUInt32(name, number); | |
UString realName = name.Mid(index); | |
if (index == 0) | |
{ | |
if(name.Left(2).CompareNoCase(L"MT") == 0) | |
{ | |
#ifndef _7ZIP_ST | |
RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); | |
#endif | |
return S_OK; | |
} | |
if (name.CompareNoCase(L"RSFX") == 0) return SetBoolProperty(_removeSfxBlock, value); | |
if (name.CompareNoCase(L"F") == 0) return SetBoolProperty(_autoFilter, value); | |
if (name.CompareNoCase(L"HC") == 0) return SetBoolProperty(_compressHeaders, value); | |
if (name.CompareNoCase(L"HCF") == 0) | |
{ | |
bool compressHeadersFull = true; | |
RINOK(SetBoolProperty(compressHeadersFull, value)); | |
if (!compressHeadersFull) | |
return E_INVALIDARG; | |
return S_OK; | |
} | |
if (name.CompareNoCase(L"HE") == 0) | |
{ | |
RINOK(SetBoolProperty(_encryptHeaders, value)); | |
_encryptHeadersSpecified = true; | |
return S_OK; | |
} | |
if (name.CompareNoCase(L"TC") == 0) return SetBoolProperty(WriteCTime, value); | |
if (name.CompareNoCase(L"TA") == 0) return SetBoolProperty(WriteATime, value); | |
if (name.CompareNoCase(L"TM") == 0) return SetBoolProperty(WriteMTime, value); | |
if (name.CompareNoCase(L"V") == 0) return SetBoolProperty(_volumeMode, value); | |
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; | |
RINOK(SetParams(oneMethodInfo, value.bstrVal)); | |
} | |
else | |
{ | |
int index = FindPropIdStart(realName); | |
if (index < 0) | |
return E_INVALIDARG; | |
const CNameToPropID &nameToPropID = g_NameToPropID[index]; | |
CProp prop; | |
prop.Id = nameToPropID.PropID; | |
if (prop.Id == NCoderPropID::kBlockSize || | |
prop.Id == NCoderPropID::kDictionarySize || | |
prop.Id == NCoderPropID::kUsedMemorySize) | |
{ | |
UInt32 dicSize; | |
RINOK(ParsePropDictionaryValue(realName.Mid(MyStringLen(nameToPropID.Name)), value, dicSize)); | |
prop.Value = dicSize; | |
if (number <= mainDicMethodIndex) | |
mainDicSize = dicSize; | |
} | |
else | |
{ | |
int index = FindPropIdExact(realName); | |
if (index < 0) | |
return E_INVALIDARG; | |
const CNameToPropID &nameToPropID = g_NameToPropID[index]; | |
prop.Id = nameToPropID.PropID; | |
if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) | |
return E_INVALIDARG; | |
} | |
oneMethodInfo.Props.Add(prop); | |
} | |
return S_OK; | |
} | |
} |