Home | History | Annotate | Download | only in Common
      1 // MethodProps.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #include "../../Common/StringToInt.h"
      6 
      7 #include "MethodProps.h"
      8 
      9 using namespace NWindows;
     10 
     11 bool StringToBool(const UString &s, bool &res)
     12 {
     13   if (s.IsEmpty() || s == L"+" || StringsAreEqualNoCase_Ascii(s, "ON"))
     14   {
     15     res = true;
     16     return true;
     17   }
     18   if (s == L"-" || StringsAreEqualNoCase_Ascii(s, "OFF"))
     19   {
     20     res = false;
     21     return true;
     22   }
     23   return false;
     24 }
     25 
     26 HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest)
     27 {
     28   switch (prop.vt)
     29   {
     30     case VT_EMPTY: dest = true; return S_OK;
     31     case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK;
     32     case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG;
     33   }
     34   return E_INVALIDARG;
     35 }
     36 
     37 unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number)
     38 {
     39   const wchar_t *start = srcString;
     40   const wchar_t *end;
     41   number = ConvertStringToUInt32(start, &end);
     42   return (unsigned)(end - start);
     43 }
     44 
     45 HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
     46 {
     47   // =VT_UI4
     48   // =VT_EMPTY
     49   // {stringUInt32}=VT_EMPTY
     50 
     51   if (prop.vt == VT_UI4)
     52   {
     53     if (!name.IsEmpty())
     54       return E_INVALIDARG;
     55     resValue = prop.ulVal;
     56     return S_OK;
     57   }
     58   if (prop.vt != VT_EMPTY)
     59     return E_INVALIDARG;
     60   if (name.IsEmpty())
     61     return S_OK;
     62   UInt32 v;
     63   if (ParseStringToUInt32(name, v) != name.Len())
     64     return E_INVALIDARG;
     65   resValue = v;
     66   return S_OK;
     67 }
     68 
     69 HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads)
     70 {
     71   if (name.IsEmpty())
     72   {
     73     switch (prop.vt)
     74     {
     75       case VT_UI4:
     76         numThreads = prop.ulVal;
     77         break;
     78       default:
     79       {
     80         bool val;
     81         RINOK(PROPVARIANT_to_bool(prop, val));
     82         numThreads = (val ? defaultNumThreads : 1);
     83         break;
     84       }
     85     }
     86     return S_OK;
     87   }
     88   if (prop.vt != VT_EMPTY)
     89     return E_INVALIDARG;
     90   return ParsePropToUInt32(name, prop, numThreads);
     91 }
     92 
     93 static HRESULT StringToDictSize(const UString &s, UInt32 &dicSize)
     94 {
     95   const wchar_t *end;
     96   UInt32 number = ConvertStringToUInt32(s, &end);
     97   unsigned numDigits = (unsigned)(end - s);
     98   if (numDigits == 0 || s.Len() > numDigits + 1)
     99     return E_INVALIDARG;
    100   const unsigned kLogDictSizeLimit = 32;
    101   if (s.Len() == numDigits)
    102   {
    103     if (number >= kLogDictSizeLimit)
    104       return E_INVALIDARG;
    105     dicSize = (UInt32)1 << (unsigned)number;
    106     return S_OK;
    107   }
    108   unsigned numBits;
    109   switch (MyCharLower_Ascii(s[numDigits]))
    110   {
    111     case 'b': dicSize = number; return S_OK;
    112     case 'k': numBits = 10; break;
    113     case 'm': numBits = 20; break;
    114     case 'g': numBits = 30; break;
    115     default: return E_INVALIDARG;
    116   }
    117   if (number >= ((UInt32)1 << (kLogDictSizeLimit - numBits)))
    118     return E_INVALIDARG;
    119   dicSize = number << numBits;
    120   return S_OK;
    121 }
    122 
    123 static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, UInt32 &resValue)
    124 {
    125   if (prop.vt == VT_UI4)
    126   {
    127     UInt32 v = prop.ulVal;
    128     if (v >= 32)
    129       return E_INVALIDARG;
    130     resValue = (UInt32)1 << v;
    131     return S_OK;
    132   }
    133   if (prop.vt == VT_BSTR)
    134     return StringToDictSize(prop.bstrVal, resValue);
    135   return E_INVALIDARG;
    136 }
    137 
    138 void CProps::AddProp32(PROPID propid, UInt32 level)
    139 {
    140   CProp prop;
    141   prop.IsOptional = true;
    142   prop.Id = propid;
    143   prop.Value = (UInt32)level;
    144   Props.Add(prop);
    145 }
    146 
    147 class CCoderProps
    148 {
    149   PROPID *_propIDs;
    150   NCOM::CPropVariant *_props;
    151   unsigned _numProps;
    152   unsigned _numPropsMax;
    153 public:
    154   CCoderProps(unsigned numPropsMax)
    155   {
    156     _numPropsMax = numPropsMax;
    157     _numProps = 0;
    158     _propIDs = new PROPID[numPropsMax];
    159     _props = new NCOM::CPropVariant[numPropsMax];
    160   }
    161   ~CCoderProps()
    162   {
    163     delete []_propIDs;
    164     delete []_props;
    165   }
    166   void AddProp(const CProp &prop);
    167   HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties)
    168   {
    169     return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps);
    170   }
    171 };
    172 
    173 void CCoderProps::AddProp(const CProp &prop)
    174 {
    175   if (_numProps >= _numPropsMax)
    176     throw 1;
    177   _propIDs[_numProps] = prop.Id;
    178   _props[_numProps] = prop.Value;
    179   _numProps++;
    180 }
    181 
    182 HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const
    183 {
    184   CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0));
    185   FOR_VECTOR (i, Props)
    186     coderProps.AddProp(Props[i]);
    187   if (dataSizeReduce)
    188   {
    189     CProp prop;
    190     prop.Id = NCoderPropID::kReduceSize;
    191     prop.Value = *dataSizeReduce;
    192     coderProps.AddProp(prop);
    193   }
    194   return coderProps.SetProps(scp);
    195 }
    196 
    197 
    198 int CMethodProps::FindProp(PROPID id) const
    199 {
    200   for (int i = Props.Size() - 1; i >= 0; i--)
    201     if (Props[i].Id == id)
    202       return i;
    203   return -1;
    204 }
    205 
    206 int CMethodProps::GetLevel() const
    207 {
    208   int i = FindProp(NCoderPropID::kLevel);
    209   if (i < 0)
    210     return 5;
    211   if (Props[i].Value.vt != VT_UI4)
    212     return 9;
    213   UInt32 level = Props[i].Value.ulVal;
    214   return level > 9 ? 9 : (int)level;
    215 }
    216 
    217 struct CNameToPropID
    218 {
    219   VARTYPE VarType;
    220   const char *Name;
    221 };
    222 
    223 static const CNameToPropID g_NameToPropID[] =
    224 {
    225   { VT_UI4, "" },
    226   { VT_UI4, "d" },
    227   { VT_UI4, "mem" },
    228   { VT_UI4, "o" },
    229   { VT_UI4, "c" },
    230   { VT_UI4, "pb" },
    231   { VT_UI4, "lc" },
    232   { VT_UI4, "lp" },
    233   { VT_UI4, "fb" },
    234   { VT_BSTR, "mf" },
    235   { VT_UI4, "mc" },
    236   { VT_UI4, "pass" },
    237   { VT_UI4, "a" },
    238   { VT_UI4, "mt" },
    239   { VT_BOOL, "eos" },
    240   { VT_UI4, "x" },
    241   { VT_UI4, "reduceSize" }
    242 };
    243 
    244 static int FindPropIdExact(const UString &name)
    245 {
    246   for (unsigned i = 0; i < ARRAY_SIZE(g_NameToPropID); i++)
    247     if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name))
    248       return i;
    249   return -1;
    250 }
    251 
    252 static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
    253 {
    254   if (varType == srcProp.vt)
    255   {
    256     destProp = srcProp;
    257     return true;
    258   }
    259   if (varType == VT_BOOL)
    260   {
    261     bool res;
    262     if (PROPVARIANT_to_bool(srcProp, res) != S_OK)
    263       return false;
    264     destProp = res;
    265     return true;
    266   }
    267   if (srcProp.vt == VT_EMPTY)
    268   {
    269     destProp = srcProp;
    270     return true;
    271   }
    272   return false;
    273 }
    274 
    275 static void SplitParams(const UString &srcString, UStringVector &subStrings)
    276 {
    277   subStrings.Clear();
    278   UString s;
    279   int len = srcString.Len();
    280   if (len == 0)
    281     return;
    282   for (int i = 0; i < len; i++)
    283   {
    284     wchar_t c = srcString[i];
    285     if (c == L':')
    286     {
    287       subStrings.Add(s);
    288       s.Empty();
    289     }
    290     else
    291       s += c;
    292   }
    293   subStrings.Add(s);
    294 }
    295 
    296 static void SplitParam(const UString &param, UString &name, UString &value)
    297 {
    298   int eqPos = param.Find(L'=');
    299   if (eqPos >= 0)
    300   {
    301     name.SetFrom(param, eqPos);
    302     value = param.Ptr(eqPos + 1);
    303     return;
    304   }
    305   unsigned i;
    306   for (i = 0; i < param.Len(); i++)
    307   {
    308     wchar_t c = param[i];
    309     if (c >= L'0' && c <= L'9')
    310       break;
    311   }
    312   name.SetFrom(param, i);
    313   value = param.Ptr(i);
    314 }
    315 
    316 static bool IsLogSizeProp(PROPID propid)
    317 {
    318   switch (propid)
    319   {
    320     case NCoderPropID::kDictionarySize:
    321     case NCoderPropID::kUsedMemorySize:
    322     case NCoderPropID::kBlockSize:
    323     case NCoderPropID::kReduceSize:
    324       return true;
    325   }
    326   return false;
    327 }
    328 
    329 HRESULT CMethodProps::SetParam(const UString &name, const UString &value)
    330 {
    331   int index = FindPropIdExact(name);
    332   if (index < 0)
    333     return E_INVALIDARG;
    334   const CNameToPropID &nameToPropID = g_NameToPropID[index];
    335   CProp prop;
    336   prop.Id = index;
    337 
    338   if (IsLogSizeProp(prop.Id))
    339   {
    340     UInt32 dicSize;
    341     RINOK(StringToDictSize(value, dicSize));
    342     prop.Value = dicSize;
    343   }
    344   else
    345   {
    346     NCOM::CPropVariant propValue;
    347     if (nameToPropID.VarType == VT_BSTR)
    348       propValue = value;
    349     else if (nameToPropID.VarType == VT_BOOL)
    350     {
    351       bool res;
    352       if (!StringToBool(value, res))
    353         return E_INVALIDARG;
    354       propValue = res;
    355     }
    356     else if (!value.IsEmpty())
    357     {
    358       UInt32 number;
    359       if (ParseStringToUInt32(value, number) == value.Len())
    360         propValue = number;
    361       else
    362         propValue = value;
    363     }
    364     if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
    365       return E_INVALIDARG;
    366   }
    367   Props.Add(prop);
    368   return S_OK;
    369 }
    370 
    371 HRESULT CMethodProps::ParseParamsFromString(const UString &srcString)
    372 {
    373   UStringVector params;
    374   SplitParams(srcString, params);
    375   FOR_VECTOR (i, params)
    376   {
    377     const UString &param = params[i];
    378     UString name, value;
    379     SplitParam(param, name, value);
    380     RINOK(SetParam(name, value));
    381   }
    382   return S_OK;
    383 }
    384 
    385 HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
    386 {
    387   if (realName.Len() == 0)
    388   {
    389     // [empty]=method
    390     return E_INVALIDARG;
    391   }
    392   if (value.vt == VT_EMPTY)
    393   {
    394     // {realName}=[empty]
    395     UString name, value;
    396     SplitParam(realName, name, value);
    397     return SetParam(name, value);
    398   }
    399 
    400   // {realName}=value
    401   int index = FindPropIdExact(realName);
    402   if (index < 0)
    403     return E_INVALIDARG;
    404   const CNameToPropID &nameToPropID = g_NameToPropID[index];
    405   CProp prop;
    406   prop.Id = index;
    407 
    408   if (IsLogSizeProp(prop.Id))
    409   {
    410     UInt32 dicSize;
    411     RINOK(PROPVARIANT_to_DictSize(value, dicSize));
    412     prop.Value = dicSize;
    413   }
    414   else
    415   {
    416     if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
    417       return E_INVALIDARG;
    418   }
    419   Props.Add(prop);
    420   return S_OK;
    421 }
    422 
    423 HRESULT COneMethodInfo::ParseMethodFromString(const UString &s)
    424 {
    425   int splitPos = s.Find(':');
    426   MethodName = s;
    427   if (splitPos < 0)
    428     return S_OK;
    429   MethodName.DeleteFrom(splitPos);
    430   return ParseParamsFromString(s.Ptr(splitPos + 1));
    431 }
    432 
    433 HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
    434 {
    435   if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m"))
    436     return ParseParamsFromPROPVARIANT(realName, value);
    437   // -m{N}=method
    438   if (value.vt != VT_BSTR)
    439     return E_INVALIDARG;
    440   return ParseMethodFromString(value.bstrVal);
    441 }
    442