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