MethodProps.cpp (11712B)
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 11 bool StringToBool(const wchar_t *s, bool &res) 12 { 13 if (s[0] == 0 || (s[0] == '+' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "ON")) 14 { 15 res = true; 16 return true; 17 } 18 if ((s[0] == '-' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "OFF")) 19 { 20 res = false; 21 return true; 22 } 23 return false; 24 } 25 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 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 45 static unsigned ParseStringToUInt64(const UString &srcString, UInt64 &number) 46 { 47 const wchar_t *start = srcString; 48 const wchar_t *end; 49 number = ConvertStringToUInt64(start, &end); 50 return (unsigned)(end - start); 51 } 52 53 HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue) 54 { 55 // =VT_UI4 56 // =VT_EMPTY 57 // {stringUInt32}=VT_EMPTY 58 59 if (prop.vt == VT_UI4) 60 { 61 if (!name.IsEmpty()) 62 return E_INVALIDARG; 63 resValue = prop.ulVal; 64 return S_OK; 65 } 66 if (prop.vt != VT_EMPTY) 67 return E_INVALIDARG; 68 if (name.IsEmpty()) 69 return S_OK; 70 UInt32 v; 71 if (ParseStringToUInt32(name, v) != name.Len()) 72 return E_INVALIDARG; 73 resValue = v; 74 return S_OK; 75 } 76 77 HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads) 78 { 79 if (name.IsEmpty()) 80 { 81 switch (prop.vt) 82 { 83 case VT_UI4: 84 numThreads = prop.ulVal; 85 break; 86 default: 87 { 88 bool val; 89 RINOK(PROPVARIANT_to_bool(prop, val)); 90 numThreads = (val ? defaultNumThreads : 1); 91 break; 92 } 93 } 94 return S_OK; 95 } 96 if (prop.vt != VT_EMPTY) 97 return E_INVALIDARG; 98 return ParsePropToUInt32(name, prop, numThreads); 99 } 100 101 102 static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp) 103 { 104 const wchar_t *end; 105 UInt32 number = ConvertStringToUInt32(s, &end); 106 unsigned numDigits = (unsigned)(end - s.Ptr()); 107 if (numDigits == 0 || s.Len() > numDigits + 1) 108 return E_INVALIDARG; 109 110 if (s.Len() == numDigits) 111 { 112 if (number >= 64) 113 return E_INVALIDARG; 114 if (number < 32) 115 destProp = (UInt32)((UInt32)1 << (unsigned)number); 116 else 117 destProp = (UInt64)((UInt64)1 << (unsigned)number); 118 return S_OK; 119 } 120 121 unsigned numBits; 122 123 switch (MyCharLower_Ascii(s[numDigits])) 124 { 125 case 'b': destProp = number; return S_OK; 126 case 'k': numBits = 10; break; 127 case 'm': numBits = 20; break; 128 case 'g': numBits = 30; break; 129 default: return E_INVALIDARG; 130 } 131 132 if (number < ((UInt32)1 << (32 - numBits))) 133 destProp = (UInt32)(number << numBits); 134 else 135 destProp = (UInt64)((UInt64)number << numBits); 136 137 return S_OK; 138 } 139 140 141 static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, NCOM::CPropVariant &destProp) 142 { 143 if (prop.vt == VT_UI4) 144 { 145 UInt32 v = prop.ulVal; 146 if (v >= 64) 147 return E_INVALIDARG; 148 if (v < 32) 149 destProp = (UInt32)((UInt32)1 << (unsigned)v); 150 else 151 destProp = (UInt64)((UInt64)1 << (unsigned)v); 152 return S_OK; 153 } 154 if (prop.vt == VT_BSTR) 155 { 156 UString s; 157 s = prop.bstrVal; 158 return StringToDictSize(s, destProp); 159 } 160 return E_INVALIDARG; 161 } 162 163 164 void CProps::AddProp32(PROPID propid, UInt32 val) 165 { 166 CProp &prop = Props.AddNew(); 167 prop.IsOptional = true; 168 prop.Id = propid; 169 prop.Value = (UInt32)val; 170 } 171 172 void CProps::AddPropBool(PROPID propid, bool val) 173 { 174 CProp &prop = Props.AddNew(); 175 prop.IsOptional = true; 176 prop.Id = propid; 177 prop.Value = val; 178 } 179 180 class CCoderProps 181 { 182 PROPID *_propIDs; 183 NCOM::CPropVariant *_props; 184 unsigned _numProps; 185 unsigned _numPropsMax; 186 public: 187 CCoderProps(unsigned numPropsMax) 188 { 189 _numPropsMax = numPropsMax; 190 _numProps = 0; 191 _propIDs = new PROPID[numPropsMax]; 192 _props = new NCOM::CPropVariant[numPropsMax]; 193 } 194 ~CCoderProps() 195 { 196 delete []_propIDs; 197 delete []_props; 198 } 199 void AddProp(const CProp &prop); 200 HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties) 201 { 202 return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps); 203 } 204 }; 205 206 void CCoderProps::AddProp(const CProp &prop) 207 { 208 if (_numProps >= _numPropsMax) 209 throw 1; 210 _propIDs[_numProps] = prop.Id; 211 _props[_numProps] = prop.Value; 212 _numProps++; 213 } 214 215 HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const 216 { 217 CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0)); 218 FOR_VECTOR (i, Props) 219 coderProps.AddProp(Props[i]); 220 if (dataSizeReduce) 221 { 222 CProp prop; 223 prop.Id = NCoderPropID::kReduceSize; 224 prop.Value = *dataSizeReduce; 225 coderProps.AddProp(prop); 226 } 227 return coderProps.SetProps(scp); 228 } 229 230 231 int CMethodProps::FindProp(PROPID id) const 232 { 233 for (int i = Props.Size() - 1; i >= 0; i--) 234 if (Props[i].Id == id) 235 return i; 236 return -1; 237 } 238 239 int CMethodProps::GetLevel() const 240 { 241 int i = FindProp(NCoderPropID::kLevel); 242 if (i < 0) 243 return 5; 244 if (Props[i].Value.vt != VT_UI4) 245 return 9; 246 UInt32 level = Props[i].Value.ulVal; 247 return level > 9 ? 9 : (int)level; 248 } 249 250 struct CNameToPropID 251 { 252 VARTYPE VarType; 253 const char *Name; 254 }; 255 256 257 // the following are related to NCoderPropID::EEnum values 258 259 static const CNameToPropID g_NameToPropID[] = 260 { 261 { VT_UI4, "" }, 262 { VT_UI4, "d" }, 263 { VT_UI4, "mem" }, 264 { VT_UI4, "o" }, 265 { VT_UI4, "c" }, 266 { VT_UI4, "pb" }, 267 { VT_UI4, "lc" }, 268 { VT_UI4, "lp" }, 269 { VT_UI4, "fb" }, 270 { VT_BSTR, "mf" }, 271 { VT_UI4, "mc" }, 272 { VT_UI4, "pass" }, 273 { VT_UI4, "a" }, 274 { VT_UI4, "mt" }, 275 { VT_BOOL, "eos" }, 276 { VT_UI4, "x" }, 277 { VT_UI8, "reduce" }, 278 { VT_UI8, "expect" }, 279 { VT_UI4, "b" }, 280 { VT_UI4, "check" }, 281 { VT_BSTR, "filter" }, 282 { VT_UI8, "memuse" } 283 }; 284 285 static int FindPropIdExact(const UString &name) 286 { 287 for (unsigned i = 0; i < ARRAY_SIZE(g_NameToPropID); i++) 288 if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name)) 289 return i; 290 return -1; 291 } 292 293 static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp) 294 { 295 if (varType == srcProp.vt) 296 { 297 destProp = srcProp; 298 return true; 299 } 300 301 if (varType == VT_UI8 && srcProp.vt == VT_UI4) 302 { 303 destProp = (UInt64)srcProp.ulVal; 304 return true; 305 } 306 307 if (varType == VT_BOOL) 308 { 309 bool res; 310 if (PROPVARIANT_to_bool(srcProp, res) != S_OK) 311 return false; 312 destProp = res; 313 return true; 314 } 315 if (srcProp.vt == VT_EMPTY) 316 { 317 destProp = srcProp; 318 return true; 319 } 320 return false; 321 } 322 323 static void SplitParams(const UString &srcString, UStringVector &subStrings) 324 { 325 subStrings.Clear(); 326 UString s; 327 unsigned len = srcString.Len(); 328 if (len == 0) 329 return; 330 for (unsigned i = 0; i < len; i++) 331 { 332 wchar_t c = srcString[i]; 333 if (c == L':') 334 { 335 subStrings.Add(s); 336 s.Empty(); 337 } 338 else 339 s += c; 340 } 341 subStrings.Add(s); 342 } 343 344 static void SplitParam(const UString ¶m, UString &name, UString &value) 345 { 346 int eqPos = param.Find(L'='); 347 if (eqPos >= 0) 348 { 349 name.SetFrom(param, eqPos); 350 value = param.Ptr(eqPos + 1); 351 return; 352 } 353 unsigned i; 354 for (i = 0; i < param.Len(); i++) 355 { 356 wchar_t c = param[i]; 357 if (c >= L'0' && c <= L'9') 358 break; 359 } 360 name.SetFrom(param, i); 361 value = param.Ptr(i); 362 } 363 364 static bool IsLogSizeProp(PROPID propid) 365 { 366 switch (propid) 367 { 368 case NCoderPropID::kDictionarySize: 369 case NCoderPropID::kUsedMemorySize: 370 case NCoderPropID::kBlockSize: 371 case NCoderPropID::kBlockSize2: 372 // case NCoderPropID::kReduceSize: 373 return true; 374 } 375 return false; 376 } 377 378 HRESULT CMethodProps::SetParam(const UString &name, const UString &value) 379 { 380 int index = FindPropIdExact(name); 381 if (index < 0) 382 return E_INVALIDARG; 383 const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index]; 384 CProp prop; 385 prop.Id = index; 386 387 if (IsLogSizeProp(prop.Id)) 388 { 389 RINOK(StringToDictSize(value, prop.Value)); 390 } 391 else 392 { 393 NCOM::CPropVariant propValue; 394 if (nameToPropID.VarType == VT_BSTR) 395 propValue = value; 396 else if (nameToPropID.VarType == VT_BOOL) 397 { 398 bool res; 399 if (!StringToBool(value, res)) 400 return E_INVALIDARG; 401 propValue = res; 402 } 403 else if (!value.IsEmpty()) 404 { 405 if (nameToPropID.VarType == VT_UI4) 406 { 407 UInt32 number; 408 if (ParseStringToUInt32(value, number) == value.Len()) 409 propValue = number; 410 else 411 propValue = value; 412 } 413 else if (nameToPropID.VarType == VT_UI8) 414 { 415 UInt64 number; 416 if (ParseStringToUInt64(value, number) == value.Len()) 417 propValue = number; 418 else 419 propValue = value; 420 } 421 else 422 propValue = value; 423 } 424 if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) 425 return E_INVALIDARG; 426 } 427 Props.Add(prop); 428 return S_OK; 429 } 430 431 HRESULT CMethodProps::ParseParamsFromString(const UString &srcString) 432 { 433 UStringVector params; 434 SplitParams(srcString, params); 435 FOR_VECTOR (i, params) 436 { 437 const UString ¶m = params[i]; 438 UString name, value; 439 SplitParam(param, name, value); 440 RINOK(SetParam(name, value)); 441 } 442 return S_OK; 443 } 444 445 HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) 446 { 447 if (realName.Len() == 0) 448 { 449 // [empty]=method 450 return E_INVALIDARG; 451 } 452 if (value.vt == VT_EMPTY) 453 { 454 // {realName}=[empty] 455 UString name, valueStr; 456 SplitParam(realName, name, valueStr); 457 return SetParam(name, valueStr); 458 } 459 460 // {realName}=value 461 int index = FindPropIdExact(realName); 462 if (index < 0) 463 return E_INVALIDARG; 464 const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index]; 465 CProp prop; 466 prop.Id = index; 467 468 if (IsLogSizeProp(prop.Id)) 469 { 470 RINOK(PROPVARIANT_to_DictSize(value, prop.Value)); 471 } 472 else 473 { 474 if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) 475 return E_INVALIDARG; 476 } 477 Props.Add(prop); 478 return S_OK; 479 } 480 481 HRESULT COneMethodInfo::ParseMethodFromString(const UString &s) 482 { 483 MethodName.Empty(); 484 int splitPos = s.Find(L':'); 485 { 486 UString temp = s; 487 if (splitPos >= 0) 488 temp.DeleteFrom(splitPos); 489 if (!temp.IsAscii()) 490 return E_INVALIDARG; 491 MethodName.SetFromWStr_if_Ascii(temp); 492 } 493 if (splitPos < 0) 494 return S_OK; 495 PropsString = s.Ptr(splitPos + 1); 496 return ParseParamsFromString(PropsString); 497 } 498 499 HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value) 500 { 501 if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m")) 502 return ParseParamsFromPROPVARIANT(realName, value); 503 // -m{N}=method 504 if (value.vt != VT_BSTR) 505 return E_INVALIDARG; 506 UString s; 507 s = value.bstrVal; 508 return ParseMethodFromString(s); 509 }