1// HandlerOut.cpp 2 3#include "StdAfx.h" 4 5#include "../../../Common/StringToInt.h" 6 7#include "../../../Windows/PropVariant.h" 8 9#ifndef _7ZIP_ST 10#include "../../../Windows/System.h" 11#endif 12 13#include "../../ICoder.h" 14 15#include "../Common/ParseProperties.h" 16 17#include "HandlerOut.h" 18 19using namespace NWindows; 20 21namespace NArchive { 22 23static const wchar_t *kCopyMethod = L"Copy"; 24static const wchar_t *kLZMAMethodName = L"LZMA"; 25static const wchar_t *kLZMA2MethodName = L"LZMA2"; 26static const wchar_t *kBZip2MethodName = L"BZip2"; 27static const wchar_t *kPpmdMethodName = L"PPMd"; 28static const wchar_t *kDeflateMethodName = L"Deflate"; 29static const wchar_t *kDeflate64MethodName = L"Deflate64"; 30 31static const wchar_t *kLzmaMatchFinderX1 = L"HC4"; 32static const wchar_t *kLzmaMatchFinderX5 = L"BT4"; 33 34static const UInt32 kLzmaAlgoX1 = 0; 35static const UInt32 kLzmaAlgoX5 = 1; 36 37static const UInt32 kLzmaDicSizeX1 = 1 << 16; 38static const UInt32 kLzmaDicSizeX3 = 1 << 20; 39static const UInt32 kLzmaDicSizeX5 = 1 << 24; 40static const UInt32 kLzmaDicSizeX7 = 1 << 25; 41static const UInt32 kLzmaDicSizeX9 = 1 << 26; 42 43static const UInt32 kLzmaFastBytesX1 = 32; 44static const UInt32 kLzmaFastBytesX7 = 64; 45 46static const UInt32 kPpmdMemSizeX1 = (1 << 22); 47static const UInt32 kPpmdMemSizeX5 = (1 << 24); 48static const UInt32 kPpmdMemSizeX7 = (1 << 26); 49static const UInt32 kPpmdMemSizeX9 = (192 << 20); 50 51static const UInt32 kPpmdOrderX1 = 4; 52static const UInt32 kPpmdOrderX5 = 6; 53static const UInt32 kPpmdOrderX7 = 16; 54static const UInt32 kPpmdOrderX9 = 32; 55 56static const UInt32 kDeflateAlgoX1 = 0; 57static const UInt32 kDeflateAlgoX5 = 1; 58 59static const UInt32 kDeflateFastBytesX1 = 32; 60static const UInt32 kDeflateFastBytesX7 = 64; 61static const UInt32 kDeflateFastBytesX9 = 128; 62 63static const UInt32 kDeflatePassesX1 = 1; 64static const UInt32 kDeflatePassesX7 = 3; 65static const UInt32 kDeflatePassesX9 = 10; 66 67static const UInt32 kBZip2NumPassesX1 = 1; 68static const UInt32 kBZip2NumPassesX7 = 2; 69static const UInt32 kBZip2NumPassesX9 = 7; 70 71static const UInt32 kBZip2DicSizeX1 = 100000; 72static const UInt32 kBZip2DicSizeX3 = 500000; 73static const UInt32 kBZip2DicSizeX5 = 900000; 74 75static const wchar_t *kDefaultMethodName = kLZMAMethodName; 76 77static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2"; 78static const UInt32 kDictionaryForHeaders = 1 << 20; 79static const UInt32 kNumFastBytesForHeaders = 273; 80static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5; 81 82static bool AreEqual(const UString &methodName, const wchar_t *s) 83 { return (methodName.CompareNoCase(s) == 0); } 84 85bool COneMethodInfo::IsLzma() const 86{ 87 return 88 AreEqual(MethodName, kLZMAMethodName) || 89 AreEqual(MethodName, kLZMA2MethodName); 90} 91 92static inline bool IsBZip2Method(const UString &methodName) 93 { return AreEqual(methodName, kBZip2MethodName); } 94 95static inline bool IsPpmdMethod(const UString &methodName) 96 { return AreEqual(methodName, kPpmdMethodName); } 97 98static inline bool IsDeflateMethod(const UString &methodName) 99{ 100 return 101 AreEqual(methodName, kDeflateMethodName) || 102 AreEqual(methodName, kDeflate64MethodName); 103} 104 105struct CNameToPropID 106{ 107 PROPID PropID; 108 VARTYPE VarType; 109 const wchar_t *Name; 110}; 111 112static CNameToPropID g_NameToPropID[] = 113{ 114 { NCoderPropID::kBlockSize, VT_UI4, L"C" }, 115 { NCoderPropID::kDictionarySize, VT_UI4, L"D" }, 116 { NCoderPropID::kUsedMemorySize, VT_UI4, L"MEM" }, 117 118 { NCoderPropID::kOrder, VT_UI4, L"O" }, 119 { NCoderPropID::kPosStateBits, VT_UI4, L"PB" }, 120 { NCoderPropID::kLitContextBits, VT_UI4, L"LC" }, 121 { NCoderPropID::kLitPosBits, VT_UI4, L"LP" }, 122 { NCoderPropID::kEndMarker, VT_BOOL, L"eos" }, 123 124 { NCoderPropID::kNumPasses, VT_UI4, L"Pass" }, 125 { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" }, 126 { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" }, 127 { NCoderPropID::kAlgorithm, VT_UI4, L"a" }, 128 { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" }, 129 { NCoderPropID::kNumThreads, VT_UI4, L"mt" }, 130 { NCoderPropID::kDefaultProp, VT_UI4, L"" } 131}; 132 133static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp) 134{ 135 if (varType == srcProp.vt) 136 { 137 destProp = srcProp; 138 return true; 139 } 140 if (varType == VT_UI1) 141 { 142 if (srcProp.vt == VT_UI4) 143 { 144 UInt32 value = srcProp.ulVal; 145 if (value > 0xFF) 146 return false; 147 destProp = (Byte)value; 148 return true; 149 } 150 } 151 else if (varType == VT_BOOL) 152 { 153 bool res; 154 if (SetBoolProperty(res, srcProp) != S_OK) 155 return false; 156 destProp = res; 157 return true; 158 } 159 return false; 160} 161 162static int FindPropIdExact(const UString &name) 163{ 164 for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++) 165 if (name.CompareNoCase(g_NameToPropID[i].Name) == 0) 166 return i; 167 return -1; 168} 169 170static int FindPropIdStart(const UString &name) 171{ 172 for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++) 173 { 174 UString t = g_NameToPropID[i].Name; 175 if (t.CompareNoCase(name.Left(t.Length())) == 0) 176 return i; 177 } 178 return -1; 179} 180 181static void SetMethodProp(COneMethodInfo &m, PROPID propID, const NCOM::CPropVariant &value) 182{ 183 for (int j = 0; j < m.Props.Size(); j++) 184 if (m.Props[j].Id == propID) 185 return; 186 CProp prop; 187 prop.Id = propID; 188 prop.Value = value; 189 m.Props.Add(prop); 190} 191 192void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo 193 #ifndef _7ZIP_ST 194 , UInt32 numThreads 195 #endif 196 ) 197{ 198 UInt32 level = _level; 199 if (oneMethodInfo.MethodName.IsEmpty()) 200 oneMethodInfo.MethodName = kDefaultMethodName; 201 202 if (oneMethodInfo.IsLzma()) 203 { 204 UInt32 dicSize = 205 (level >= 9 ? kLzmaDicSizeX9 : 206 (level >= 7 ? kLzmaDicSizeX7 : 207 (level >= 5 ? kLzmaDicSizeX5 : 208 (level >= 3 ? kLzmaDicSizeX3 : 209 kLzmaDicSizeX1)))); 210 211 UInt32 algo = 212 (level >= 5 ? kLzmaAlgoX5 : 213 kLzmaAlgoX1); 214 215 UInt32 fastBytes = 216 (level >= 7 ? kLzmaFastBytesX7 : 217 kLzmaFastBytesX1); 218 219 const wchar_t *matchFinder = 220 (level >= 5 ? kLzmaMatchFinderX5 : 221 kLzmaMatchFinderX1); 222 223 SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize); 224 SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo); 225 SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes); 226 SetMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder); 227 #ifndef _7ZIP_ST 228 SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); 229 #endif 230 } 231 else if (IsDeflateMethod(oneMethodInfo.MethodName)) 232 { 233 UInt32 fastBytes = 234 (level >= 9 ? kDeflateFastBytesX9 : 235 (level >= 7 ? kDeflateFastBytesX7 : 236 kDeflateFastBytesX1)); 237 238 UInt32 numPasses = 239 (level >= 9 ? kDeflatePassesX9 : 240 (level >= 7 ? kDeflatePassesX7 : 241 kDeflatePassesX1)); 242 243 UInt32 algo = 244 (level >= 5 ? kDeflateAlgoX5 : 245 kDeflateAlgoX1); 246 247 SetMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo); 248 SetMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes); 249 SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses); 250 } 251 else if (IsBZip2Method(oneMethodInfo.MethodName)) 252 { 253 UInt32 numPasses = 254 (level >= 9 ? kBZip2NumPassesX9 : 255 (level >= 7 ? kBZip2NumPassesX7 : 256 kBZip2NumPassesX1)); 257 258 UInt32 dicSize = 259 (level >= 5 ? kBZip2DicSizeX5 : 260 (level >= 3 ? kBZip2DicSizeX3 : 261 kBZip2DicSizeX1)); 262 263 SetMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses); 264 SetMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize); 265 #ifndef _7ZIP_ST 266 SetMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads); 267 #endif 268 } 269 else if (IsPpmdMethod(oneMethodInfo.MethodName)) 270 { 271 UInt32 useMemSize = 272 (level >= 9 ? kPpmdMemSizeX9 : 273 (level >= 7 ? kPpmdMemSizeX7 : 274 (level >= 5 ? kPpmdMemSizeX5 : 275 kPpmdMemSizeX1))); 276 277 UInt32 order = 278 (level >= 9 ? kPpmdOrderX9 : 279 (level >= 7 ? kPpmdOrderX7 : 280 (level >= 5 ? kPpmdOrderX5 : 281 kPpmdOrderX1))); 282 283 SetMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize); 284 SetMethodProp(oneMethodInfo, NCoderPropID::kOrder, order); 285 } 286} 287 288static void SplitParams(const UString &srcString, UStringVector &subStrings) 289{ 290 subStrings.Clear(); 291 UString name; 292 int len = srcString.Length(); 293 if (len == 0) 294 return; 295 for (int i = 0; i < len; i++) 296 { 297 wchar_t c = srcString[i]; 298 if (c == L':') 299 { 300 subStrings.Add(name); 301 name.Empty(); 302 } 303 else 304 name += c; 305 } 306 subStrings.Add(name); 307} 308 309static void SplitParam(const UString ¶m, UString &name, UString &value) 310{ 311 int eqPos = param.Find(L'='); 312 if (eqPos >= 0) 313 { 314 name = param.Left(eqPos); 315 value = param.Mid(eqPos + 1); 316 return; 317 } 318 for(int i = 0; i < param.Length(); i++) 319 { 320 wchar_t c = param[i]; 321 if (c >= L'0' && c <= L'9') 322 { 323 name = param.Left(i); 324 value = param.Mid(i); 325 return; 326 } 327 } 328 name = param; 329} 330 331HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value) 332{ 333 CProp prop; 334 int index = FindPropIdExact(name); 335 if (index < 0) 336 return E_INVALIDARG; 337 const CNameToPropID &nameToPropID = g_NameToPropID[index]; 338 prop.Id = nameToPropID.PropID; 339 340 if (prop.Id == NCoderPropID::kBlockSize || 341 prop.Id == NCoderPropID::kDictionarySize || 342 prop.Id == NCoderPropID::kUsedMemorySize) 343 { 344 UInt32 dicSize; 345 RINOK(ParsePropDictionaryValue(value, dicSize)); 346 prop.Value = dicSize; 347 } 348 else 349 { 350 NCOM::CPropVariant propValue; 351 352 if (nameToPropID.VarType == VT_BSTR) 353 propValue = value; 354 else if (nameToPropID.VarType == VT_BOOL) 355 { 356 bool res; 357 if (!StringToBool(value, res)) 358 return E_INVALIDARG; 359 propValue = res; 360 } 361 else 362 { 363 UInt32 number; 364 if (ParseStringToUInt32(value, number) == value.Length()) 365 propValue = number; 366 else 367 propValue = value; 368 } 369 370 if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value)) 371 return E_INVALIDARG; 372 } 373 oneMethodInfo.Props.Add(prop); 374 return S_OK; 375} 376 377HRESULT COutHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString) 378{ 379 UStringVector params; 380 SplitParams(srcString, params); 381 if (params.Size() > 0) 382 oneMethodInfo.MethodName = params[0]; 383 for (int i = 1; i < params.Size(); i++) 384 { 385 const UString ¶m = params[i]; 386 UString name, value; 387 SplitParam(param, name, value); 388 RINOK(SetParam(oneMethodInfo, name, value)); 389 } 390 return S_OK; 391} 392 393HRESULT COutHandler::SetSolidSettings(const UString &s) 394{ 395 UString s2 = s; 396 s2.MakeUpper(); 397 for (int i = 0; i < s2.Length();) 398 { 399 const wchar_t *start = ((const wchar_t *)s2) + i; 400 const wchar_t *end; 401 UInt64 v = ConvertStringToUInt64(start, &end); 402 if (start == end) 403 { 404 if (s2[i++] != 'E') 405 return E_INVALIDARG; 406 _solidExtension = true; 407 continue; 408 } 409 i += (int)(end - start); 410 if (i == s2.Length()) 411 return E_INVALIDARG; 412 wchar_t c = s2[i++]; 413 switch(c) 414 { 415 case 'F': 416 if (v < 1) 417 v = 1; 418 _numSolidFiles = v; 419 break; 420 case 'B': 421 _numSolidBytes = v; 422 _numSolidBytesDefined = true; 423 break; 424 case 'K': 425 _numSolidBytes = (v << 10); 426 _numSolidBytesDefined = true; 427 break; 428 case 'M': 429 _numSolidBytes = (v << 20); 430 _numSolidBytesDefined = true; 431 break; 432 case 'G': 433 _numSolidBytes = (v << 30); 434 _numSolidBytesDefined = true; 435 break; 436 default: 437 return E_INVALIDARG; 438 } 439 } 440 return S_OK; 441} 442 443HRESULT COutHandler::SetSolidSettings(const PROPVARIANT &value) 444{ 445 bool isSolid; 446 switch(value.vt) 447 { 448 case VT_EMPTY: 449 isSolid = true; 450 break; 451 case VT_BOOL: 452 isSolid = (value.boolVal != VARIANT_FALSE); 453 break; 454 case VT_BSTR: 455 if (StringToBool(value.bstrVal, isSolid)) 456 break; 457 return SetSolidSettings(value.bstrVal); 458 default: 459 return E_INVALIDARG; 460 } 461 if (isSolid) 462 InitSolid(); 463 else 464 _numSolidFiles = 1; 465 return S_OK; 466} 467 468void COutHandler::Init() 469{ 470 _removeSfxBlock = false; 471 _compressHeaders = true; 472 _encryptHeadersSpecified = false; 473 _encryptHeaders = false; 474 475 WriteCTime = false; 476 WriteATime = false; 477 WriteMTime = true; 478 479 #ifndef _7ZIP_ST 480 _numThreads = NSystem::GetNumberOfProcessors(); 481 #endif 482 483 _level = 5; 484 _autoFilter = true; 485 _volumeMode = false; 486 _crcSize = 4; 487 InitSolid(); 488} 489 490void COutHandler::BeforeSetProperty() 491{ 492 Init(); 493 #ifndef _7ZIP_ST 494 numProcessors = NSystem::GetNumberOfProcessors(); 495 #endif 496 497 mainDicSize = 0xFFFFFFFF; 498 mainDicMethodIndex = 0xFFFFFFFF; 499 minNumber = 0; 500 _crcSize = 4; 501} 502 503HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) 504{ 505 UString name = nameSpec; 506 name.MakeUpper(); 507 if (name.IsEmpty()) 508 return E_INVALIDARG; 509 510 if (name[0] == 'X') 511 { 512 name.Delete(0); 513 _level = 9; 514 return ParsePropValue(name, value, _level); 515 } 516 517 if (name[0] == L'S') 518 { 519 name.Delete(0); 520 if (name.IsEmpty()) 521 return SetSolidSettings(value); 522 if (value.vt != VT_EMPTY) 523 return E_INVALIDARG; 524 return SetSolidSettings(name); 525 } 526 527 if (name == L"CRC") 528 { 529 _crcSize = 4; 530 name.Delete(0, 3); 531 return ParsePropValue(name, value, _crcSize); 532 } 533 534 UInt32 number; 535 int index = ParseStringToUInt32(name, number); 536 UString realName = name.Mid(index); 537 if (index == 0) 538 { 539 if(name.Left(2).CompareNoCase(L"MT") == 0) 540 { 541 #ifndef _7ZIP_ST 542 RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); 543 #endif 544 return S_OK; 545 } 546 if (name.CompareNoCase(L"RSFX") == 0) return SetBoolProperty(_removeSfxBlock, value); 547 if (name.CompareNoCase(L"F") == 0) return SetBoolProperty(_autoFilter, value); 548 if (name.CompareNoCase(L"HC") == 0) return SetBoolProperty(_compressHeaders, value); 549 if (name.CompareNoCase(L"HCF") == 0) 550 { 551 bool compressHeadersFull = true; 552 RINOK(SetBoolProperty(compressHeadersFull, value)); 553 if (!compressHeadersFull) 554 return E_INVALIDARG; 555 return S_OK; 556 } 557 if (name.CompareNoCase(L"HE") == 0) 558 { 559 RINOK(SetBoolProperty(_encryptHeaders, value)); 560 _encryptHeadersSpecified = true; 561 return S_OK; 562 } 563 if (name.CompareNoCase(L"TC") == 0) return SetBoolProperty(WriteCTime, value); 564 if (name.CompareNoCase(L"TA") == 0) return SetBoolProperty(WriteATime, value); 565 if (name.CompareNoCase(L"TM") == 0) return SetBoolProperty(WriteMTime, value); 566 if (name.CompareNoCase(L"V") == 0) return SetBoolProperty(_volumeMode, value); 567 number = 0; 568 } 569 if (number > 10000) 570 return E_FAIL; 571 if (number < minNumber) 572 return E_INVALIDARG; 573 number -= minNumber; 574 for(int j = _methods.Size(); j <= (int)number; j++) 575 { 576 COneMethodInfo oneMethodInfo; 577 _methods.Add(oneMethodInfo); 578 } 579 580 COneMethodInfo &oneMethodInfo = _methods[number]; 581 582 if (realName.Length() == 0) 583 { 584 if (value.vt != VT_BSTR) 585 return E_INVALIDARG; 586 587 RINOK(SetParams(oneMethodInfo, value.bstrVal)); 588 } 589 else 590 { 591 int index = FindPropIdStart(realName); 592 if (index < 0) 593 return E_INVALIDARG; 594 const CNameToPropID &nameToPropID = g_NameToPropID[index]; 595 CProp prop; 596 prop.Id = nameToPropID.PropID; 597 598 if (prop.Id == NCoderPropID::kBlockSize || 599 prop.Id == NCoderPropID::kDictionarySize || 600 prop.Id == NCoderPropID::kUsedMemorySize) 601 { 602 UInt32 dicSize; 603 RINOK(ParsePropDictionaryValue(realName.Mid(MyStringLen(nameToPropID.Name)), value, dicSize)); 604 prop.Value = dicSize; 605 if (number <= mainDicMethodIndex) 606 mainDicSize = dicSize; 607 } 608 else 609 { 610 int index = FindPropIdExact(realName); 611 if (index < 0) 612 return E_INVALIDARG; 613 const CNameToPropID &nameToPropID = g_NameToPropID[index]; 614 prop.Id = nameToPropID.PropID; 615 if (!ConvertProperty(value, nameToPropID.VarType, prop.Value)) 616 return E_INVALIDARG; 617 } 618 oneMethodInfo.Props.Add(prop); 619 } 620 return S_OK; 621} 622 623} 624