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 
257 // the following are related to NCoderPropID::EEnum values
258 
259 static const CNameToPropID g_NameToPropID[] =
260 {
261   { VT_UI4, "" },
262   { VT_UI4, "d" },
263   { VT_UI4, "mem" },
264   { VT_UI4, "o" },
265   { VT_UI4, "c" },
266   { VT_UI4, "pb" },
267   { VT_UI4, "lc" },
268   { VT_UI4, "lp" },
269   { VT_UI4, "fb" },
270   { VT_BSTR, "mf" },
271   { VT_UI4, "mc" },
272   { VT_UI4, "pass" },
273   { VT_UI4, "a" },
274   { VT_UI4, "mt" },
275   { VT_BOOL, "eos" },
276   { VT_UI4, "x" },
277   { VT_UI8, "reduce" },
278   { VT_UI8, "expect" },
279   { VT_UI4, "b" },
280   { VT_UI4, "check" },
281   { VT_BSTR, "filter" },
282   { VT_UI8, "memuse" }
283 };
284 
FindPropIdExact(const UString & name)285 static int FindPropIdExact(const UString &name)
286 {
287   for (unsigned i = 0; i < ARRAY_SIZE(g_NameToPropID); i++)
288     if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name))
289       return i;
290   return -1;
291 }
292 
ConvertProperty(const PROPVARIANT & srcProp,VARTYPE varType,NCOM::CPropVariant & destProp)293 static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
294 {
295   if (varType == srcProp.vt)
296   {
297     destProp = srcProp;
298     return true;
299   }
300 
301   if (varType == VT_UI8 && srcProp.vt == VT_UI4)
302   {
303     destProp = (UInt64)srcProp.ulVal;
304     return true;
305   }
306 
307   if (varType == VT_BOOL)
308   {
309     bool res;
310     if (PROPVARIANT_to_bool(srcProp, res) != S_OK)
311       return false;
312     destProp = res;
313     return true;
314   }
315   if (srcProp.vt == VT_EMPTY)
316   {
317     destProp = srcProp;
318     return true;
319   }
320   return false;
321 }
322 
SplitParams(const UString & srcString,UStringVector & subStrings)323 static void SplitParams(const UString &srcString, UStringVector &subStrings)
324 {
325   subStrings.Clear();
326   UString s;
327   unsigned len = srcString.Len();
328   if (len == 0)
329     return;
330   for (unsigned i = 0; i < len; i++)
331   {
332     wchar_t c = srcString[i];
333     if (c == L':')
334     {
335       subStrings.Add(s);
336       s.Empty();
337     }
338     else
339       s += c;
340   }
341   subStrings.Add(s);
342 }
343 
SplitParam(const UString & param,UString & name,UString & value)344 static void SplitParam(const UString &param, UString &name, UString &value)
345 {
346   int eqPos = param.Find(L'=');
347   if (eqPos >= 0)
348   {
349     name.SetFrom(param, eqPos);
350     value = param.Ptr(eqPos + 1);
351     return;
352   }
353   unsigned i;
354   for (i = 0; i < param.Len(); i++)
355   {
356     wchar_t c = param[i];
357     if (c >= L'0' && c <= L'9')
358       break;
359   }
360   name.SetFrom(param, i);
361   value = param.Ptr(i);
362 }
363 
IsLogSizeProp(PROPID propid)364 static bool IsLogSizeProp(PROPID propid)
365 {
366   switch (propid)
367   {
368     case NCoderPropID::kDictionarySize:
369     case NCoderPropID::kUsedMemorySize:
370     case NCoderPropID::kBlockSize:
371     case NCoderPropID::kBlockSize2:
372     // case NCoderPropID::kReduceSize:
373       return true;
374   }
375   return false;
376 }
377 
SetParam(const UString & name,const UString & value)378 HRESULT CMethodProps::SetParam(const UString &name, const UString &value)
379 {
380   int index = FindPropIdExact(name);
381   if (index < 0)
382     return E_INVALIDARG;
383   const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
384   CProp prop;
385   prop.Id = index;
386 
387   if (IsLogSizeProp(prop.Id))
388   {
389     RINOK(StringToDictSize(value, prop.Value));
390   }
391   else
392   {
393     NCOM::CPropVariant propValue;
394     if (nameToPropID.VarType == VT_BSTR)
395       propValue = value;
396     else if (nameToPropID.VarType == VT_BOOL)
397     {
398       bool res;
399       if (!StringToBool(value, res))
400         return E_INVALIDARG;
401       propValue = res;
402     }
403     else if (!value.IsEmpty())
404     {
405       if (nameToPropID.VarType == VT_UI4)
406       {
407         UInt32 number;
408         if (ParseStringToUInt32(value, number) == value.Len())
409           propValue = number;
410         else
411           propValue = value;
412       }
413       else if (nameToPropID.VarType == VT_UI8)
414       {
415         UInt64 number;
416         if (ParseStringToUInt64(value, number) == value.Len())
417           propValue = number;
418         else
419           propValue = value;
420       }
421       else
422         propValue = value;
423     }
424     if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
425       return E_INVALIDARG;
426   }
427   Props.Add(prop);
428   return S_OK;
429 }
430 
ParseParamsFromString(const UString & srcString)431 HRESULT CMethodProps::ParseParamsFromString(const UString &srcString)
432 {
433   UStringVector params;
434   SplitParams(srcString, params);
435   FOR_VECTOR (i, params)
436   {
437     const UString &param = params[i];
438     UString name, value;
439     SplitParam(param, name, value);
440     RINOK(SetParam(name, value));
441   }
442   return S_OK;
443 }
444 
ParseParamsFromPROPVARIANT(const UString & realName,const PROPVARIANT & value)445 HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
446 {
447   if (realName.Len() == 0)
448   {
449     // [empty]=method
450     return E_INVALIDARG;
451   }
452   if (value.vt == VT_EMPTY)
453   {
454     // {realName}=[empty]
455     UString name, valueStr;
456     SplitParam(realName, name, valueStr);
457     return SetParam(name, valueStr);
458   }
459 
460   // {realName}=value
461   int index = FindPropIdExact(realName);
462   if (index < 0)
463     return E_INVALIDARG;
464   const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
465   CProp prop;
466   prop.Id = index;
467 
468   if (IsLogSizeProp(prop.Id))
469   {
470     RINOK(PROPVARIANT_to_DictSize(value, prop.Value));
471   }
472   else
473   {
474     if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
475       return E_INVALIDARG;
476   }
477   Props.Add(prop);
478   return S_OK;
479 }
480 
ParseMethodFromString(const UString & s)481 HRESULT COneMethodInfo::ParseMethodFromString(const UString &s)
482 {
483   MethodName.Empty();
484   int splitPos = s.Find(L':');
485   {
486     UString temp = s;
487     if (splitPos >= 0)
488       temp.DeleteFrom(splitPos);
489     if (!temp.IsAscii())
490       return E_INVALIDARG;
491     MethodName.SetFromWStr_if_Ascii(temp);
492   }
493   if (splitPos < 0)
494     return S_OK;
495   PropsString = s.Ptr(splitPos + 1);
496   return ParseParamsFromString(PropsString);
497 }
498 
ParseMethodFromPROPVARIANT(const UString & realName,const PROPVARIANT & value)499 HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
500 {
501   if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m"))
502     return ParseParamsFromPROPVARIANT(realName, value);
503   // -m{N}=method
504   if (value.vt != VT_BSTR)
505     return E_INVALIDARG;
506   UString s;
507   s = value.bstrVal;
508   return ParseMethodFromString(s);
509 }
510