// MethodProps.cpp | |
#include "StdAfx.h" | |
#include "../../Common/StringToInt.h" | |
#include "MethodProps.h" | |
using namespace NWindows; | |
bool StringToBool(const UString &s, bool &res) | |
{ | |
if (s.IsEmpty() || s == L"+" || StringsAreEqualNoCase_Ascii(s, "ON")) | |
{ | |
res = true; | |
return true; | |
} | |
if (s == L"-" || StringsAreEqualNoCase_Ascii(s, "OFF")) | |
{ | |
res = false; | |
return true; | |
} | |
return false; | |
} | |
HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest) | |
{ | |
switch (prop.vt) | |
{ | |
case VT_EMPTY: dest = true; return S_OK; | |
case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK; | |
case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG; | |
} | |
return E_INVALIDARG; | |
} | |
unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number) | |
{ | |
const wchar_t *start = srcString; | |
const wchar_t *end; | |
number = ConvertStringToUInt32(start, &end); | |
return (unsigned)(end - start); | |
} | |
HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) | |
{ | |
// =VT_UI4 | |
// =VT_EMPTY | |
// {stringUInt32}=VT_EMPTY | |
if (prop.vt == VT_UI4) | |
{ | |
if (!name.IsEmpty()) | |
return E_INVALIDARG; | |
resValue = prop.ulVal; | |
return S_OK; | |
} | |
if (prop.vt != VT_EMPTY) | |
return E_INVALIDARG; | |
if (name.IsEmpty()) | |
return S_OK; | |
UInt32 v; | |
if (ParseStringToUInt32(name, v) != name.Len()) | |
return E_INVALIDARG; | |
resValue = v; | |
return S_OK; | |
} | |
HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads) | |
{ | |
if (name.IsEmpty()) | |
{ | |
switch (prop.vt) | |
{ | |
case VT_UI4: | |
numThreads = prop.ulVal; | |
break; | |
default: | |
{ | |
bool val; | |
RINOK(PROPVARIANT_to_bool(prop, val)); | |
numThreads = (val ? defaultNumThreads : 1); | |
break; | |
} | |
} | |
return S_OK; | |
} | |
if (prop.vt != VT_EMPTY) | |
return E_INVALIDARG; | |
return ParsePropToUInt32(name, prop, numThreads); | |
} | |
static HRESULT StringToDictSize(const UString &s, UInt32 &dicSize) | |
{ | |
const wchar_t *end; | |
UInt32 number = ConvertStringToUInt32(s, &end); | |
unsigned numDigits = (unsigned)(end - s); | |
if (numDigits == 0 || s.Len() > numDigits + 1) | |
return E_INVALIDARG; | |
const unsigned kLogDictSizeLimit = 32; | |
if (s.Len() == numDigits) | |
{ | |
if (number >= kLogDictSizeLimit) | |
return E_INVALIDARG; | |
dicSize = (UInt32)1 << (unsigned)number; | |
return S_OK; | |
} | |
unsigned numBits; | |
switch (MyCharLower_Ascii(s[numDigits])) | |
{ | |
case 'b': dicSize = number; return S_OK; | |
case 'k': numBits = 10; break; | |
case 'm': numBits = 20; break; | |
case 'g': numBits = 30; break; | |
default: return E_INVALIDARG; | |
} | |
if (number >= ((UInt32)1 << (kLogDictSizeLimit - numBits))) | |
return E_INVALIDARG; | |
dicSize = number << numBits; | |
return S_OK; | |
} | |
static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, UInt32 &resValue) | |
{ | |
if (prop.vt == VT_UI4) | |
{ | |
UInt32 v = prop.ulVal; | |
if (v >= 32) | |
return E_INVALIDARG; | |
resValue = (UInt32)1 << v; | |
return S_OK; | |
} | |
if (prop.vt == VT_BSTR) | |
return StringToDictSize(prop.bstrVal, resValue); | |
return E_INVALIDARG; | |
} | |
void CProps::AddProp32(PROPID propid, UInt32 level) | |
{ | |
CProp prop; | |
prop.IsOptional = true; | |
prop.Id = propid; | |
prop.Value = (UInt32)level; | |
Props.Add(prop); | |
} | |
class CCoderProps | |
{ | |
PROPID *_propIDs; | |
NCOM::CPropVariant *_props; | |
unsigned _numProps; | |
unsigned _numPropsMax; | |
public: | |
CCoderProps(unsigned numPropsMax) | |
{ | |
_numPropsMax = numPropsMax; | |
_numProps = 0; | |
_propIDs = new PROPID[numPropsMax]; | |
_props = new NCOM::CPropVariant[numPropsMax]; | |
} | |
~CCoderProps() | |
{ | |
delete []_propIDs; | |
delete []_props; | |
} | |
void AddProp(const CProp &prop); | |
HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties) | |
{ | |
return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps); | |
} | |
}; | |
void CCoderProps::AddProp(const CProp &prop) | |
{ | |
if (_numProps >= _numPropsMax) | |
throw 1; | |
_propIDs[_numProps] = prop.Id; | |
_props[_numProps] = prop.Value; | |
_numProps++; | |
} | |
HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const | |
{ | |
CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0)); | |
FOR_VECTOR (i, Props) | |
coderProps.AddProp(Props[i]); | |
if (dataSizeReduce) | |
{ | |
CProp prop; | |
prop.Id = NCoderPropID::kReduceSize; | |
prop.Value = *dataSizeReduce; | |
coderProps.AddProp(prop); | |
} | |
return coderProps.SetProps(scp); | |
} | |
int CMethodProps::FindProp(PROPID id) const | |
{ | |
for (int i = Props.Size() - 1; i >= 0; i--) | |
if (Props[i].Id == id) | |
return i; | |
return -1; | |
} | |
int CMethodProps::GetLevel() const | |
{ | |
int i = FindProp(NCoderPropID::kLevel); | |
if (i < 0) | |
return 5; | |
if (Props[i].Value.vt != VT_UI4) | |
return 9; | |
UInt32 level = Props[i].Value.ulVal; | |
return level > 9 ? 9 : (int)level; | |
} | |
struct CNameToPropID | |
{ | |
VARTYPE VarType; | |
const char *Name; | |
}; | |
static const CNameToPropID g_NameToPropID[] = | |
{ | |
{ VT_UI4, "" }, | |
{ VT_UI4, "d" }, | |
{ VT_UI4, "mem" }, | |
{ VT_UI4, "o" }, | |
{ VT_UI4, "c" }, | |
{ VT_UI4, "pb" }, | |
{ VT_UI4, "lc" }, | |
{ VT_UI4, "lp" }, | |
{ VT_UI4, "fb" }, | |
{ VT_BSTR, "mf" }, | |
{ VT_UI4, "mc" }, | |
{ VT_UI4, "pass" }, | |
{ VT_UI4, "a" }, | |
{ VT_UI4, "mt" }, | |
{ VT_BOOL, "eos" }, | |
{ VT_UI4, "x" }, | |
{ VT_UI4, "reduceSize" } | |
}; | |
static int FindPropIdExact(const UString &name) | |
{ | |
for (unsigned i = 0; i < ARRAY_SIZE(g_NameToPropID); i++) | |
if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name)) | |
return i; | |
return -1; | |
} | |
static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp) | |
{ | |
if (varType == srcProp.vt) | |
{ | |
destProp = srcProp; | |
return true; | |
} | |
if (varType == VT_BOOL) | |
{ | |
bool res; | |
if (PROPVARIANT_to_bool(srcProp, res) != S_OK) | |
return false; | |
destProp = res; | |
return true; | |
} | |
if (srcProp.vt == VT_EMPTY) | |
{ | |
destProp = srcProp; | |
return true; | |
} | |
return false; | |
} | |
static void SplitParams(const UString &srcString, UStringVector &subStrings) | |
{ | |
subStrings.Clear(); | |
UString s; | |
int len = srcString.Len(); | |
if (len == 0) | |
return; | |
for (int i = 0; i < len; i++) | |
{ | |
wchar_t c = srcString[i]; | |
if (c == L':') | |
{ | |
subStrings.Add(s); | |
s.Empty(); | |
} | |
else | |
s += c; | |
} | |
subStrings.Add(s); | |
} | |
static void SplitParam(const UString ¶m, UString &name, UString &value) | |
{ | |
int eqPos = param.Find(L'='); | |
if (eqPos >= 0) | |
{ | |
name.SetFrom(param, eqPos); | |
value = param.Ptr(eqPos + 1); | |
return; | |
} | |
unsigned i; | |
for (i = 0; i < param.Len(); i++) | |
{ | |
wchar_t c = param[i]; | |
if (c >= L'0' && c <= L'9') | |
break; | |
} | |
name.SetFrom(param, i); | |
value = param.Ptr(i); | |
} | |
static bool IsLogSizeProp(PROPID propid) | |
{ | |
switch (propid) | |
{ | |
case NCoderPropID::kDictionarySize: | |
case NCoderPropID::kUsedMemorySize: | |
case NCoderPropID::kBlockSize: | |
case NCoderPropID::kReduceSize: | |
return true; | |
} | |
return false; | |
} | |
HRESULT CMethodProps::SetParam(const UString &name, const UString &value) | |
{ | |
int index = FindPropIdExact(name); | |
if (index < 0) | |
return E_INVALIDARG; | |
const CNameToPropID &nameToPropID = g_NameToPropID[index]; | |
CProp prop; | |
prop.Id = index; | |
if (IsLogSizeProp(prop.Id)) | |
{ | |
UInt32 dicSize; | |
RINOK(StringToDictSize(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 if (!value.IsEmpty()) | |
{ | |
UInt32 number; | |
if (ParseStringToUInt32(value, number) == value.Len()) | |
propValue = number; | |
else | |
propValue = value; | |
} | |
if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) | |
return E_INVALIDARG; | |
} | |
Props.Add(prop); | |
return S_OK; | |
} | |
HRESULT CMethodProps::ParseParamsFromString(const UString &srcString) | |
{ | |
UStringVector params; | |
SplitParams(srcString, params); | |
FOR_VECTOR (i, params) | |
{ | |
const UString ¶m = params[i]; | |
UString name, value; | |
SplitParam(param, name, value); | |
RINOK(SetParam(name, value)); | |
} | |
return S_OK; | |
} | |
HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) | |
{ | |
if (realName.Len() == 0) | |
{ | |
// [empty]=method | |
return E_INVALIDARG; | |
} | |
if (value.vt == VT_EMPTY) | |
{ | |
// {realName}=[empty] | |
UString name, value; | |
SplitParam(realName, name, value); | |
return SetParam(name, value); | |
} | |
// {realName}=value | |
int index = FindPropIdExact(realName); | |
if (index < 0) | |
return E_INVALIDARG; | |
const CNameToPropID &nameToPropID = g_NameToPropID[index]; | |
CProp prop; | |
prop.Id = index; | |
if (IsLogSizeProp(prop.Id)) | |
{ | |
UInt32 dicSize; | |
RINOK(PROPVARIANT_to_DictSize(value, dicSize)); | |
prop.Value = dicSize; | |
} | |
else | |
{ | |
if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) | |
return E_INVALIDARG; | |
} | |
Props.Add(prop); | |
return S_OK; | |
} | |
HRESULT COneMethodInfo::ParseMethodFromString(const UString &s) | |
{ | |
int splitPos = s.Find(':'); | |
MethodName = s; | |
if (splitPos < 0) | |
return S_OK; | |
MethodName.DeleteFrom(splitPos); | |
return ParseParamsFromString(s.Ptr(splitPos + 1)); | |
} | |
HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) | |
{ | |
if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m")) | |
return ParseParamsFromPROPVARIANT(realName, value); | |
// -m{N}=method | |
if (value.vt != VT_BSTR) | |
return E_INVALIDARG; | |
return ParseMethodFromString(value.bstrVal); | |
} |