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