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