• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &param, 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 &param = 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