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
Calc_From_Val_Percents(UInt64 val,UInt64 percents)11 UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents)
12 {
13 // if (percents == 0) return 0;
14 const UInt64 q = percents / 100;
15 const UInt32 r = (UInt32)(percents % 100);
16 UInt64 res = 0;
17
18 if (q != 0)
19 {
20 if (val > (UInt64)(Int64)-1 / q)
21 return (UInt64)(Int64)-1;
22 res = val * q;
23 }
24
25 if (r != 0)
26 {
27 UInt64 v2;
28 if (val <= (UInt64)(Int64)-1 / r)
29 v2 = val * r / 100;
30 else
31 v2 = val / 100 * r;
32 res += v2;
33 if (res < v2)
34 return (UInt64)(Int64)-1;
35 }
36
37 return res;
38 }
39
40
StringToBool(const wchar_t * s,bool & res)41 bool StringToBool(const wchar_t *s, bool &res)
42 {
43 if (s[0] == 0 || (s[0] == '+' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "ON"))
44 {
45 res = true;
46 return true;
47 }
48 if ((s[0] == '-' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "OFF"))
49 {
50 res = false;
51 return true;
52 }
53 return false;
54 }
55
PROPVARIANT_to_bool(const PROPVARIANT & prop,bool & dest)56 HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest)
57 {
58 switch (prop.vt)
59 {
60 case VT_EMPTY: dest = true; return S_OK;
61 case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK;
62 case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG;
63 }
64 return E_INVALIDARG;
65 }
66
ParseStringToUInt32(const UString & srcString,UInt32 & number)67 unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number)
68 {
69 const wchar_t *start = srcString;
70 const wchar_t *end;
71 number = ConvertStringToUInt32(start, &end);
72 return (unsigned)(end - start);
73 }
74
ParseStringToUInt64(const UString & srcString,UInt64 & number)75 static unsigned ParseStringToUInt64(const UString &srcString, UInt64 &number)
76 {
77 const wchar_t *start = srcString;
78 const wchar_t *end;
79 number = ConvertStringToUInt64(start, &end);
80 return (unsigned)(end - start);
81 }
82
ParsePropToUInt32(const UString & name,const PROPVARIANT & prop,UInt32 & resValue)83 HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
84 {
85 // =VT_UI4
86 // =VT_EMPTY : it doesn't change (resValue), and returns S_OK
87 // {stringUInt32}=VT_EMPTY
88
89 if (prop.vt == VT_UI4)
90 {
91 if (!name.IsEmpty())
92 return E_INVALIDARG;
93 resValue = prop.ulVal;
94 return S_OK;
95 }
96 if (prop.vt != VT_EMPTY)
97 return E_INVALIDARG;
98 if (name.IsEmpty())
99 return S_OK;
100 UInt32 v;
101 if (ParseStringToUInt32(name, v) != name.Len())
102 return E_INVALIDARG;
103 resValue = v;
104 return S_OK;
105 }
106
107
108
ParseMtProp2(const UString & name,const PROPVARIANT & prop,UInt32 & numThreads,bool & force)109 HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force)
110 {
111 force = false;
112 UString s;
113 if (name.IsEmpty())
114 {
115 if (prop.vt == VT_UI4)
116 {
117 numThreads = prop.ulVal;
118 force = true;
119 return S_OK;
120 }
121 bool val;
122 HRESULT res = PROPVARIANT_to_bool(prop, val);
123 if (res == S_OK)
124 {
125 if (!val)
126 {
127 numThreads = 1;
128 force = true;
129 }
130 // force = true; for debug
131 // "(VT_BOOL = VARIANT_TRUE)" set "force = false" and doesn't change numThreads
132 return S_OK;
133 }
134 if (prop.vt != VT_BSTR)
135 return res;
136 s.SetFromBstr(prop.bstrVal);
137 if (s.IsEmpty())
138 return E_INVALIDARG;
139 }
140 else
141 {
142 if (prop.vt != VT_EMPTY)
143 return E_INVALIDARG;
144 s = name;
145 }
146
147 s.MakeLower_Ascii();
148 const wchar_t *start = s;
149 UInt32 v = numThreads;
150
151 /* we force up, if threads number specified
152 only `d` will force it down */
153 bool force_loc = true;
154 for (;;)
155 {
156 const wchar_t c = *start;
157 if (!c)
158 break;
159 if (c == 'd')
160 {
161 force_loc = false; // force down
162 start++;
163 continue;
164 }
165 if (c == 'u')
166 {
167 force_loc = true; // force up
168 start++;
169 continue;
170 }
171 bool isPercent = false;
172 if (c == 'p')
173 {
174 isPercent = true;
175 start++;
176 }
177 const wchar_t *end;
178 v = ConvertStringToUInt32(start, &end);
179 if (end == start)
180 return E_INVALIDARG;
181 if (isPercent)
182 v = numThreads * v / 100;
183 start = end;
184 }
185
186 numThreads = v;
187 force = force_loc;
188 return S_OK;
189 }
190
191
192
SetLogSizeProp(UInt64 number,NCOM::CPropVariant & destProp)193 static HRESULT SetLogSizeProp(UInt64 number, NCOM::CPropVariant &destProp)
194 {
195 if (number >= 64)
196 return E_INVALIDARG;
197 UInt32 val32;
198 if (number < 32)
199 val32 = (UInt32)1 << (unsigned)number;
200 /*
201 else if (number == 32 && reduce_4GB_to_32bits)
202 val32 = (UInt32)(Int32)-1;
203 */
204 else
205 {
206 destProp = (UInt64)((UInt64)1 << (unsigned)number);
207 return S_OK;
208 }
209 destProp = (UInt32)val32;
210 return S_OK;
211 }
212
213
StringToDictSize(const UString & s,NCOM::CPropVariant & destProp)214 static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp)
215 {
216 /* if (reduce_4GB_to_32bits) we can reduce (4 GiB) property to (4 GiB - 1).
217 to fit the value to UInt32 for clients that do not support 64-bit values */
218
219 const wchar_t *end;
220 const UInt64 number = ConvertStringToUInt64(s, &end);
221 const unsigned numDigits = (unsigned)(end - s.Ptr());
222 if (numDigits == 0 || s.Len() > numDigits + 1)
223 return E_INVALIDARG;
224
225 if (s.Len() == numDigits)
226 return SetLogSizeProp(number, destProp);
227
228 unsigned numBits;
229
230 switch (MyCharLower_Ascii(s[numDigits]))
231 {
232 case 'b': numBits = 0; break;
233 case 'k': numBits = 10; break;
234 case 'm': numBits = 20; break;
235 case 'g': numBits = 30; break;
236 default: return E_INVALIDARG;
237 }
238
239 const UInt64 range4g = ((UInt64)1 << (32 - numBits));
240 if (number < range4g)
241 destProp = (UInt32)((UInt32)number << numBits);
242 /*
243 else if (number == range4g && reduce_4GB_to_32bits)
244 destProp = (UInt32)(Int32)-1;
245 */
246 else if (numBits == 0)
247 destProp = (UInt64)number;
248 else if (number >= ((UInt64)1 << (64 - numBits)))
249 return E_INVALIDARG;
250 else
251 destProp = (UInt64)((UInt64)number << numBits);
252 return S_OK;
253 }
254
255
PROPVARIANT_to_DictSize(const PROPVARIANT & prop,NCOM::CPropVariant & destProp)256 static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, NCOM::CPropVariant &destProp)
257 {
258 if (prop.vt == VT_UI4)
259 return SetLogSizeProp(prop.ulVal, destProp);
260
261 if (prop.vt == VT_BSTR)
262 {
263 UString s;
264 s = prop.bstrVal;
265 return StringToDictSize(s, destProp);
266 }
267 return E_INVALIDARG;
268 }
269
270
AddProp32(PROPID propid,UInt32 val)271 void CProps::AddProp32(PROPID propid, UInt32 val)
272 {
273 CProp &prop = Props.AddNew();
274 prop.IsOptional = true;
275 prop.Id = propid;
276 prop.Value = (UInt32)val;
277 }
278
AddPropBool(PROPID propid,bool val)279 void CProps::AddPropBool(PROPID propid, bool val)
280 {
281 CProp &prop = Props.AddNew();
282 prop.IsOptional = true;
283 prop.Id = propid;
284 prop.Value = val;
285 }
286
287 class CCoderProps
288 {
289 PROPID *_propIDs;
290 NCOM::CPropVariant *_props;
291 unsigned _numProps;
292 unsigned _numPropsMax;
293 public:
CCoderProps(unsigned numPropsMax)294 CCoderProps(unsigned numPropsMax):
295 _propIDs(NULL),
296 _props(NULL),
297 _numProps(0),
298 _numPropsMax(numPropsMax)
299 {
300 _propIDs = new PROPID[numPropsMax];
301 _props = new NCOM::CPropVariant[numPropsMax];
302 }
~CCoderProps()303 ~CCoderProps()
304 {
305 delete []_propIDs;
306 delete []_props;
307 }
308 void AddProp(const CProp &prop);
SetProps(ICompressSetCoderProperties * setCoderProperties)309 HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties)
310 {
311 return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps);
312 }
313 };
314
AddProp(const CProp & prop)315 void CCoderProps::AddProp(const CProp &prop)
316 {
317 if (_numProps >= _numPropsMax)
318 throw 1;
319 _propIDs[_numProps] = prop.Id;
320 _props[_numProps] = prop.Value;
321 _numProps++;
322 }
323
SetCoderProps(ICompressSetCoderProperties * scp,const UInt64 * dataSizeReduce) const324 HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const
325 {
326 return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL);
327 }
328
SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties * scp,const UInt64 * dataSizeReduce,const UInt64 * affinity) const329 HRESULT CProps::SetCoderProps_DSReduce_Aff(
330 ICompressSetCoderProperties *scp,
331 const UInt64 *dataSizeReduce,
332 const UInt64 *affinity) const
333 {
334 CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0) + (affinity ? 1 : 0) );
335 FOR_VECTOR (i, Props)
336 coderProps.AddProp(Props[i]);
337 if (dataSizeReduce)
338 {
339 CProp prop;
340 prop.Id = NCoderPropID::kReduceSize;
341 prop.Value = *dataSizeReduce;
342 coderProps.AddProp(prop);
343 }
344 if (affinity)
345 {
346 CProp prop;
347 prop.Id = NCoderPropID::kAffinity;
348 prop.Value = *affinity;
349 coderProps.AddProp(prop);
350 }
351 return coderProps.SetProps(scp);
352 }
353
354
FindProp(PROPID id) const355 int CMethodProps::FindProp(PROPID id) const
356 {
357 for (unsigned i = Props.Size(); i != 0;)
358 if (Props[--i].Id == id)
359 return (int)i;
360 return -1;
361 }
362
GetLevel() const363 unsigned CMethodProps::GetLevel() const
364 {
365 int i = FindProp(NCoderPropID::kLevel);
366 if (i < 0)
367 return 5;
368 if (Props[(unsigned)i].Value.vt != VT_UI4)
369 return 9;
370 UInt32 level = Props[(unsigned)i].Value.ulVal;
371 return level > 9 ? 9 : (unsigned)level;
372 }
373
374 struct CNameToPropID
375 {
376 VARTYPE VarType;
377 const char *Name;
378 };
379
380
381 // the following are related to NCoderPropID::EEnum values
382 // NCoderPropID::k_NUM_DEFINED
383 static const CNameToPropID g_NameToPropID[] =
384 {
385 { VT_UI4, "" },
386 { VT_UI4, "d" },
387 { VT_UI4, "mem" },
388 { VT_UI4, "o" },
389 { VT_UI8, "c" },
390 { VT_UI4, "pb" },
391 { VT_UI4, "lc" },
392 { VT_UI4, "lp" },
393 { VT_UI4, "fb" },
394 { VT_BSTR, "mf" },
395 { VT_UI4, "mc" },
396 { VT_UI4, "pass" },
397 { VT_UI4, "a" },
398 { VT_UI4, "mt" },
399 { VT_BOOL, "eos" },
400 { VT_UI4, "x" },
401 { VT_UI8, "reduce" },
402 { VT_UI8, "expect" },
403 { VT_UI8, "cc" }, // "cc" in v23, "b" in v22.01
404 { VT_UI4, "check" },
405 { VT_BSTR, "filter" },
406 { VT_UI8, "memuse" },
407 { VT_UI8, "aff" },
408 { VT_UI4, "offset" },
409 { VT_UI4, "zhb" }
410 /*
411 ,
412 // { VT_UI4, "zhc" },
413 // { VT_UI4, "zhd" },
414 // { VT_UI4, "zcb" },
415 { VT_UI4, "dc" },
416 { VT_UI4, "zx" },
417 { VT_UI4, "zf" },
418 { VT_UI4, "zmml" },
419 { VT_UI4, "zov" },
420 { VT_BOOL, "zmfr" },
421 { VT_BOOL, "zle" }, // long enable
422 // { VT_UI4, "zldb" },
423 { VT_UI4, "zld" },
424 { VT_UI4, "zlhb" },
425 { VT_UI4, "zlmml" },
426 { VT_UI4, "zlbb" },
427 { VT_UI4, "zlhrb" },
428 { VT_BOOL, "zwus" },
429 { VT_BOOL, "zshp" },
430 { VT_BOOL, "zshs" },
431 { VT_BOOL, "zshe" },
432 { VT_BOOL, "zshg" },
433 { VT_UI4, "zpsm" }
434 */
435 // { VT_UI4, "mcb" }, // mc log version
436 // { VT_UI4, "ztlen" }, // fb ?
437 };
438
439 /*
440 #if defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 200410L) || (defined(_MSC_VER) && _MSC_VER >= 1600)
441
442 #if (defined(__cplusplus) && __cplusplus < 201103L) \
443 && defined(__clang__) && __clang_major__ >= 4
444 #pragma GCC diagnostic ignored "-Wc11-extensions"
445 #endif
446 static_assert(Z7_ARRAY_SIZE(g_NameToPropID) == NCoderPropID::k_NUM_DEFINED,
447 "g_NameToPropID doesn't match NCoderPropID enum");
448 #endif
449 */
450
FindPropIdExact(const UString & name)451 static int FindPropIdExact(const UString &name)
452 {
453 for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NameToPropID); i++)
454 if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name))
455 return (int)i;
456 return -1;
457 }
458
ConvertProperty(const PROPVARIANT & srcProp,VARTYPE varType,NCOM::CPropVariant & destProp)459 static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
460 {
461 if (varType == srcProp.vt)
462 {
463 destProp = srcProp;
464 return true;
465 }
466
467 if (varType == VT_UI8 && srcProp.vt == VT_UI4)
468 {
469 destProp = (UInt64)srcProp.ulVal;
470 return true;
471 }
472
473 if (varType == VT_BOOL)
474 {
475 bool res;
476 if (PROPVARIANT_to_bool(srcProp, res) != S_OK)
477 return false;
478 destProp = res;
479 return true;
480 }
481 if (srcProp.vt == VT_EMPTY)
482 {
483 destProp = srcProp;
484 return true;
485 }
486 return false;
487 }
488
SplitParams(const UString & srcString,UStringVector & subStrings)489 static void SplitParams(const UString &srcString, UStringVector &subStrings)
490 {
491 subStrings.Clear();
492 UString s;
493 unsigned len = srcString.Len();
494 if (len == 0)
495 return;
496 for (unsigned i = 0; i < len; i++)
497 {
498 wchar_t c = srcString[i];
499 if (c == L':')
500 {
501 subStrings.Add(s);
502 s.Empty();
503 }
504 else
505 s += c;
506 }
507 subStrings.Add(s);
508 }
509
SplitParam(const UString & param,UString & name,UString & value)510 static void SplitParam(const UString ¶m, UString &name, UString &value)
511 {
512 int eqPos = param.Find(L'=');
513 if (eqPos >= 0)
514 {
515 name.SetFrom(param, (unsigned)eqPos);
516 value = param.Ptr((unsigned)(eqPos + 1));
517 return;
518 }
519 unsigned i;
520 for (i = 0; i < param.Len(); i++)
521 {
522 wchar_t c = param[i];
523 if (c >= L'0' && c <= L'9')
524 break;
525 }
526 name.SetFrom(param, i);
527 value = param.Ptr(i);
528 }
529
IsLogSizeProp(PROPID propid)530 static bool IsLogSizeProp(PROPID propid)
531 {
532 switch (propid)
533 {
534 case NCoderPropID::kDictionarySize:
535 case NCoderPropID::kUsedMemorySize:
536 case NCoderPropID::kBlockSize:
537 case NCoderPropID::kBlockSize2:
538 /*
539 case NCoderPropID::kChainSize:
540 case NCoderPropID::kLdmWindowSize:
541 */
542 // case NCoderPropID::kReduceSize:
543 return true;
544 }
545 return false;
546 }
547
SetParam(const UString & name,const UString & value)548 HRESULT CMethodProps::SetParam(const UString &name, const UString &value)
549 {
550 int index = FindPropIdExact(name);
551 if (index < 0)
552 {
553 // 'b' was used as NCoderPropID::kBlockSize2 before v23
554 if (!name.IsEqualTo_Ascii_NoCase("b") || value.Find(L':') >= 0)
555 return E_INVALIDARG;
556 index = NCoderPropID::kBlockSize2;
557 }
558 const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
559 CProp prop;
560 prop.Id = (unsigned)index;
561
562 if (IsLogSizeProp(prop.Id))
563 {
564 RINOK(StringToDictSize(value, prop.Value))
565 }
566 else
567 {
568 NCOM::CPropVariant propValue;
569 if (nameToPropID.VarType == VT_BSTR)
570 propValue = value;
571 else if (nameToPropID.VarType == VT_BOOL)
572 {
573 bool res;
574 if (!StringToBool(value, res))
575 return E_INVALIDARG;
576 propValue = res;
577 }
578 else if (!value.IsEmpty())
579 {
580 if (nameToPropID.VarType == VT_UI4)
581 {
582 UInt32 number;
583 if (ParseStringToUInt32(value, number) == value.Len())
584 propValue = number;
585 else
586 propValue = value;
587 }
588 else if (nameToPropID.VarType == VT_UI8)
589 {
590 UInt64 number;
591 if (ParseStringToUInt64(value, number) == value.Len())
592 propValue = number;
593 else
594 propValue = value;
595 }
596 else
597 propValue = value;
598 }
599 if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
600 return E_INVALIDARG;
601 }
602 Props.Add(prop);
603 return S_OK;
604 }
605
ParseParamsFromString(const UString & srcString)606 HRESULT CMethodProps::ParseParamsFromString(const UString &srcString)
607 {
608 UStringVector params;
609 SplitParams(srcString, params);
610 FOR_VECTOR (i, params)
611 {
612 const UString ¶m = params[i];
613 UString name, value;
614 SplitParam(param, name, value);
615 RINOK(SetParam(name, value))
616 }
617 return S_OK;
618 }
619
ParseParamsFromPROPVARIANT(const UString & realName,const PROPVARIANT & value)620 HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
621 {
622 if (realName.Len() == 0)
623 {
624 // [empty]=method
625 return E_INVALIDARG;
626 }
627 if (value.vt == VT_EMPTY)
628 {
629 // {realName}=[empty]
630 UString name, valueStr;
631 SplitParam(realName, name, valueStr);
632 return SetParam(name, valueStr);
633 }
634
635 // {realName}=value
636 const int index = FindPropIdExact(realName);
637 if (index < 0)
638 return E_INVALIDARG;
639 const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
640 CProp prop;
641 prop.Id = (unsigned)index;
642
643 if (IsLogSizeProp(prop.Id))
644 {
645 RINOK(PROPVARIANT_to_DictSize(value, prop.Value))
646 }
647 else
648 {
649 if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
650 return E_INVALIDARG;
651 }
652 Props.Add(prop);
653 return S_OK;
654 }
655
656
GetMemoryUsage_LZMA(UInt32 dict,bool isBt,UInt32 numThreads)657 static UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads)
658 {
659 UInt32 hs = dict - 1;
660 hs |= (hs >> 1);
661 hs |= (hs >> 2);
662 hs |= (hs >> 4);
663 hs |= (hs >> 8);
664 hs >>= 1;
665 if (hs >= (1 << 24))
666 hs >>= 1;
667 hs |= (1 << 16) - 1;
668 // if (numHashBytes >= 5)
669 if (!isBt)
670 hs |= (256 << 10) - 1;
671 hs++;
672 UInt64 size1 = (UInt64)hs * 4;
673 size1 += (UInt64)dict * 4;
674 if (isBt)
675 size1 += (UInt64)dict * 4;
676 size1 += (2 << 20);
677
678 if (numThreads > 1 && isBt)
679 size1 += (2 << 20) + (4 << 20);
680 return size1;
681 }
682
683 static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28;
684
Get_Lzma_MemUsage(bool addSlidingWindowSize) const685 UInt64 CMethodProps::Get_Lzma_MemUsage(bool addSlidingWindowSize) const
686 {
687 const UInt64 dicSize = Get_Lzma_DicSize();
688 const bool isBt = Get_Lzma_MatchFinder_IsBt();
689 const UInt32 dict32 = (dicSize >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dicSize);
690 const UInt32 numThreads = Get_Lzma_NumThreads();
691 UInt64 size = GetMemoryUsage_LZMA(dict32, isBt, numThreads);
692
693 if (addSlidingWindowSize)
694 {
695 const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16);
696 UInt64 blockSize = (UInt64)dict32 + (1 << 16)
697 + (numThreads > 1 ? (1 << 20) : 0);
698 blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2));
699 if (blockSize >= kBlockSizeMax)
700 blockSize = kBlockSizeMax;
701 size += blockSize;
702 }
703 return size;
704 }
705
706
707
708
ParseMethodFromString(const UString & s)709 HRESULT COneMethodInfo::ParseMethodFromString(const UString &s)
710 {
711 MethodName.Empty();
712 int splitPos = s.Find(L':');
713 {
714 UString temp = s;
715 if (splitPos >= 0)
716 temp.DeleteFrom((unsigned)splitPos);
717 if (!temp.IsAscii())
718 return E_INVALIDARG;
719 MethodName.SetFromWStr_if_Ascii(temp);
720 }
721 if (splitPos < 0)
722 return S_OK;
723 PropsString = s.Ptr((unsigned)(splitPos + 1));
724 return ParseParamsFromString(PropsString);
725 }
726
ParseMethodFromPROPVARIANT(const UString & realName,const PROPVARIANT & value)727 HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
728 {
729 if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m"))
730 return ParseParamsFromPROPVARIANT(realName, value);
731 // -m{N}=method
732 if (value.vt != VT_BSTR)
733 return E_INVALIDARG;
734 UString s;
735 s = value.bstrVal;
736 return ParseMethodFromString(s);
737 }
738