xref: /aosp_15_r20/external/lzma/CPP/7zip/Common/MethodProps.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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 &param, 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 &param = 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