| // 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); | |
| } |