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