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