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