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