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