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