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 ¶m, 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 ¶m = 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