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