1 // 7zHandlerOut.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../Common/ComTry.h" 6 #include "../../../Common/StringToInt.h" 7 #include "../../../Common/Wildcard.h" 8 9 #include "../Common/ItemNameUtils.h" 10 #include "../Common/ParseProperties.h" 11 12 #include "7zHandler.h" 13 #include "7zOut.h" 14 #include "7zUpdate.h" 15 16 using namespace NWindows; 17 18 namespace NArchive { 19 namespace N7z { 20 21 static const wchar_t *k_LZMA_Name = L"LZMA"; 22 static const wchar_t *kDefaultMethodName = L"LZMA2"; 23 static const wchar_t *k_Copy_Name = L"Copy"; 24 25 static const wchar_t *k_MatchFinder_ForHeaders = L"BT2"; 26 static const UInt32 k_NumFastBytes_ForHeaders = 273; 27 static const UInt32 k_Level_ForHeaders = 5; 28 static const UInt32 k_Dictionary_ForHeaders = 29 #ifdef UNDER_CE 30 1 << 18; 31 #else 32 1 << 20; 33 #endif 34 35 STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type) 36 { 37 *type = NFileTimeType::kWindows; 38 return S_OK; 39 } 40 41 HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m) 42 { 43 if (!FindMethod( 44 EXTERNAL_CODECS_VARS 45 m.MethodName, dest.Id, dest.NumInStreams, dest.NumOutStreams)) 46 return E_INVALIDARG; 47 (CProps &)dest = (CProps &)m; 48 return S_OK; 49 } 50 51 HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod) 52 { 53 if (!_compressHeaders) 54 return S_OK; 55 COneMethodInfo m; 56 m.MethodName = k_LZMA_Name; 57 m.AddPropString(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders); 58 m.AddProp32(NCoderPropID::kLevel, k_Level_ForHeaders); 59 m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders); 60 m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders); 61 m.AddNumThreadsProp(1); 62 63 CMethodFull methodFull; 64 RINOK(PropsMethod_To_FullMethod(methodFull, m)); 65 headerMethod.Methods.Add(methodFull); 66 return S_OK; 67 } 68 69 void CHandler::AddDefaultMethod() 70 { 71 FOR_VECTOR (i, _methods) 72 { 73 UString &methodName = _methods[i].MethodName; 74 if (methodName.IsEmpty()) 75 methodName = kDefaultMethodName; 76 } 77 if (_methods.IsEmpty()) 78 { 79 COneMethodInfo m; 80 m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName); 81 _methods.Add(m); 82 } 83 } 84 85 HRESULT CHandler::SetMainMethod( 86 CCompressionMethodMode &methodMode, 87 CObjectVector<COneMethodInfo> &methods 88 #ifndef _7ZIP_ST 89 , UInt32 numThreads 90 #endif 91 ) 92 { 93 AddDefaultMethod(); 94 95 const UInt64 kSolidBytes_Min = (1 << 24); 96 const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1; 97 98 bool needSolid = false; 99 FOR_VECTOR (i, methods) 100 { 101 COneMethodInfo &oneMethodInfo = methods[i]; 102 SetGlobalLevelAndThreads(oneMethodInfo 103 #ifndef _7ZIP_ST 104 , numThreads 105 #endif 106 ); 107 108 CMethodFull methodFull; 109 RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo)); 110 methodMode.Methods.Add(methodFull); 111 112 if (methodFull.Id != k_Copy) 113 needSolid = true; 114 115 if (_numSolidBytesDefined) 116 continue; 117 118 UInt32 dicSize; 119 switch (methodFull.Id) 120 { 121 case k_LZMA: 122 case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break; 123 case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break; 124 case k_Deflate: dicSize = (UInt32)1 << 15; break; 125 case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break; 126 default: continue; 127 } 128 _numSolidBytes = (UInt64)dicSize << 7; 129 if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min; 130 if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max; 131 _numSolidBytesDefined = true; 132 } 133 134 if (!_numSolidBytesDefined) 135 if (needSolid) 136 _numSolidBytes = kSolidBytes_Max; 137 else 138 _numSolidBytes = 0; 139 _numSolidBytesDefined = true; 140 return S_OK; 141 } 142 143 static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined) 144 { 145 // ft = 0; 146 // ftDefined = false; 147 NCOM::CPropVariant prop; 148 RINOK(updateCallback->GetProperty(index, propID, &prop)); 149 if (prop.vt == VT_FILETIME) 150 { 151 ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32); 152 ftDefined = true; 153 } 154 else if (prop.vt != VT_EMPTY) 155 return E_INVALIDARG; 156 else 157 { 158 ft = 0; 159 ftDefined = false; 160 } 161 return S_OK; 162 } 163 164 /* 165 166 #ifdef _WIN32 167 static const wchar_t kDirDelimiter1 = L'\\'; 168 #endif 169 static const wchar_t kDirDelimiter2 = L'/'; 170 171 static inline bool IsCharDirLimiter(wchar_t c) 172 { 173 return ( 174 #ifdef _WIN32 175 c == kDirDelimiter1 || 176 #endif 177 c == kDirDelimiter2); 178 } 179 180 static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex) 181 { 182 CTreeFolder &tf = treeFolders[cur]; 183 tf.SortIndex = curSortIndex++; 184 for (int i = 0; i < tf.SubFolders.Size(); i++) 185 curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex); 186 tf.SortIndexEnd = curSortIndex; 187 return curSortIndex; 188 } 189 190 static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos) 191 { 192 const CIntVector &subFolders = treeFolders[cur].SubFolders; 193 int left = 0, right = subFolders.Size(); 194 insertPos = -1; 195 for (;;) 196 { 197 if (left == right) 198 { 199 insertPos = left; 200 return -1; 201 } 202 int mid = (left + right) / 2; 203 int midFolder = subFolders[mid]; 204 int compare = CompareFileNames(name, treeFolders[midFolder].Name); 205 if (compare == 0) 206 return midFolder; 207 if (compare < 0) 208 right = mid; 209 else 210 left = mid + 1; 211 } 212 } 213 214 static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name) 215 { 216 int insertPos; 217 int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos); 218 if (folderIndex < 0) 219 { 220 folderIndex = treeFolders.Size(); 221 CTreeFolder &newFolder = treeFolders.AddNew(); 222 newFolder.Parent = cur; 223 newFolder.Name = name; 224 treeFolders[cur].SubFolders.Insert(insertPos, folderIndex); 225 } 226 // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234; 227 return folderIndex; 228 } 229 */ 230 231 STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, 232 IArchiveUpdateCallback *updateCallback) 233 { 234 COM_TRY_BEGIN 235 236 const CDbEx *db = 0; 237 #ifdef _7Z_VOL 238 if (_volumes.Size() > 1) 239 return E_FAIL; 240 const CVolume *volume = 0; 241 if (_volumes.Size() == 1) 242 { 243 volume = &_volumes.Front(); 244 db = &volume->Database; 245 } 246 #else 247 if (_inStream != 0) 248 db = &_db; 249 #endif 250 251 /* 252 CMyComPtr<IArchiveGetRawProps> getRawProps; 253 updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); 254 255 CUniqBlocks secureBlocks; 256 secureBlocks.AddUniq(NULL, 0); 257 258 CObjectVector<CTreeFolder> treeFolders; 259 { 260 CTreeFolder folder; 261 folder.Parent = -1; 262 treeFolders.Add(folder); 263 } 264 */ 265 266 CObjectVector<CUpdateItem> updateItems; 267 268 bool need_CTime = (Write_CTime.Def && Write_CTime.Val); 269 bool need_ATime = (Write_ATime.Def && Write_ATime.Val); 270 bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def); 271 if (db) 272 { 273 if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); 274 if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); 275 if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); 276 } 277 278 UString s; 279 280 for (UInt32 i = 0; i < numItems; i++) 281 { 282 Int32 newData, newProps; 283 UInt32 indexInArchive; 284 if (!updateCallback) 285 return E_FAIL; 286 RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); 287 CUpdateItem ui; 288 ui.NewProps = IntToBool(newProps); 289 ui.NewData = IntToBool(newData); 290 ui.IndexInArchive = indexInArchive; 291 ui.IndexInClient = i; 292 ui.IsAnti = false; 293 ui.Size = 0; 294 295 UString name; 296 // bool isAltStream = false; 297 if (ui.IndexInArchive != -1) 298 { 299 if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size()) 300 return E_INVALIDARG; 301 const CFileItem &fi = db->Files[ui.IndexInArchive]; 302 if (!ui.NewProps) 303 { 304 _db.GetPath(ui.IndexInArchive, name); 305 } 306 ui.IsDir = fi.IsDir; 307 ui.Size = fi.Size; 308 // isAltStream = fi.IsAltStream; 309 ui.IsAnti = db->IsItemAnti(ui.IndexInArchive); 310 311 if (!ui.NewProps) 312 { 313 ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); 314 ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); 315 ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); 316 } 317 } 318 319 if (ui.NewProps) 320 { 321 bool folderStatusIsDefined; 322 { 323 NCOM::CPropVariant prop; 324 RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop)); 325 if (prop.vt == VT_EMPTY) 326 ui.AttribDefined = false; 327 else if (prop.vt != VT_UI4) 328 return E_INVALIDARG; 329 else 330 { 331 ui.Attrib = prop.ulVal; 332 ui.AttribDefined = true; 333 } 334 } 335 336 // we need MTime to sort files. 337 if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined)); 338 if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined)); 339 if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined)); 340 341 /* 342 if (getRawProps) 343 { 344 const void *data; 345 UInt32 dataSize; 346 UInt32 propType; 347 348 getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); 349 if (dataSize != 0 && propType != NPropDataType::kRaw) 350 return E_FAIL; 351 ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize); 352 } 353 */ 354 355 { 356 NCOM::CPropVariant prop; 357 RINOK(updateCallback->GetProperty(i, kpidPath, &prop)); 358 if (prop.vt == VT_EMPTY) 359 { 360 } 361 else if (prop.vt != VT_BSTR) 362 return E_INVALIDARG; 363 else 364 { 365 name = NItemName::MakeLegalName(prop.bstrVal); 366 } 367 } 368 { 369 NCOM::CPropVariant prop; 370 RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop)); 371 if (prop.vt == VT_EMPTY) 372 folderStatusIsDefined = false; 373 else if (prop.vt != VT_BOOL) 374 return E_INVALIDARG; 375 else 376 { 377 ui.IsDir = (prop.boolVal != VARIANT_FALSE); 378 folderStatusIsDefined = true; 379 } 380 } 381 382 { 383 NCOM::CPropVariant prop; 384 RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop)); 385 if (prop.vt == VT_EMPTY) 386 ui.IsAnti = false; 387 else if (prop.vt != VT_BOOL) 388 return E_INVALIDARG; 389 else 390 ui.IsAnti = (prop.boolVal != VARIANT_FALSE); 391 } 392 393 /* 394 { 395 NCOM::CPropVariant prop; 396 RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop)); 397 if (prop.vt == VT_EMPTY) 398 isAltStream = false; 399 else if (prop.vt != VT_BOOL) 400 return E_INVALIDARG; 401 else 402 isAltStream = (prop.boolVal != VARIANT_FALSE); 403 } 404 */ 405 406 if (ui.IsAnti) 407 { 408 ui.AttribDefined = false; 409 410 ui.CTimeDefined = false; 411 ui.ATimeDefined = false; 412 ui.MTimeDefined = false; 413 414 ui.Size = 0; 415 } 416 417 if (!folderStatusIsDefined && ui.AttribDefined) 418 ui.SetDirStatusFromAttrib(); 419 } 420 else 421 { 422 /* 423 if (_db.SecureIDs.IsEmpty()) 424 ui.SecureIndex = secureBlocks.AddUniq(NULL, 0); 425 else 426 { 427 int id = _db.SecureIDs[ui.IndexInArchive]; 428 size_t offs = _db.SecureOffsets[id]; 429 size_t size = _db.SecureOffsets[id + 1] - offs; 430 ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size); 431 } 432 */ 433 } 434 435 /* 436 { 437 int folderIndex = 0; 438 if (_useParents) 439 { 440 int j; 441 s.Empty(); 442 for (j = 0; j < name.Len(); j++) 443 { 444 wchar_t c = name[j]; 445 if (IsCharDirLimiter(c)) 446 { 447 folderIndex = AddFolder(treeFolders, folderIndex, s); 448 s.Empty(); 449 continue; 450 } 451 s += c; 452 } 453 if (isAltStream) 454 { 455 int colonPos = s.Find(':'); 456 if (colonPos < 0) 457 { 458 // isAltStream = false; 459 return E_INVALIDARG; 460 } 461 UString mainName = s.Left(colonPos); 462 int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName); 463 if (treeFolders[newFolderIndex].UpdateItemIndex < 0) 464 { 465 for (int j = updateItems.Size() - 1; j >= 0; j--) 466 { 467 CUpdateItem &ui2 = updateItems[j]; 468 if (ui2.ParentFolderIndex == folderIndex 469 && ui2.Name == mainName) 470 { 471 ui2.TreeFolderIndex = newFolderIndex; 472 treeFolders[newFolderIndex].UpdateItemIndex = j; 473 } 474 } 475 } 476 folderIndex = newFolderIndex; 477 s.Delete(0, colonPos + 1); 478 } 479 ui.Name = s; 480 } 481 else 482 ui.Name = name; 483 ui.IsAltStream = isAltStream; 484 ui.ParentFolderIndex = folderIndex; 485 ui.TreeFolderIndex = -1; 486 if (ui.IsDir && !s.IsEmpty()) 487 { 488 ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s); 489 treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size(); 490 } 491 } 492 */ 493 ui.Name = name; 494 495 if (ui.NewData) 496 { 497 NCOM::CPropVariant prop; 498 RINOK(updateCallback->GetProperty(i, kpidSize, &prop)); 499 if (prop.vt != VT_UI8) 500 return E_INVALIDARG; 501 ui.Size = (UInt64)prop.uhVal.QuadPart; 502 if (ui.Size != 0 && ui.IsAnti) 503 return E_INVALIDARG; 504 } 505 updateItems.Add(ui); 506 } 507 508 /* 509 FillSortIndex(treeFolders, 0, 0); 510 for (i = 0; i < (UInt32)updateItems.Size(); i++) 511 { 512 CUpdateItem &ui = updateItems[i]; 513 ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex; 514 ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd; 515 } 516 */ 517 518 CCompressionMethodMode methodMode, headerMethod; 519 520 HRESULT res = SetMainMethod(methodMode, _methods 521 #ifndef _7ZIP_ST 522 , _numThreads 523 #endif 524 ); 525 RINOK(res); 526 methodMode.Binds = _binds; 527 528 RINOK(SetHeaderMethod(headerMethod)); 529 #ifndef _7ZIP_ST 530 methodMode.NumThreads = _numThreads; 531 headerMethod.NumThreads = 1; 532 #endif 533 534 CMyComPtr<ICryptoGetTextPassword2> getPassword2; 535 updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2); 536 537 methodMode.PasswordIsDefined = false; 538 methodMode.Password.Empty(); 539 if (getPassword2) 540 { 541 CMyComBSTR password; 542 Int32 passwordIsDefined; 543 RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)); 544 methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); 545 if (methodMode.PasswordIsDefined && (BSTR)password) 546 methodMode.Password = password; 547 } 548 549 bool compressMainHeader = _compressHeaders; // check it 550 551 bool encryptHeaders = false; 552 553 if (methodMode.PasswordIsDefined) 554 { 555 if (_encryptHeadersSpecified) 556 encryptHeaders = _encryptHeaders; 557 #ifndef _NO_CRYPTO 558 else 559 encryptHeaders = _passwordIsDefined; 560 #endif 561 compressMainHeader = true; 562 if (encryptHeaders) 563 { 564 headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined; 565 headerMethod.Password = methodMode.Password; 566 } 567 } 568 569 if (numItems < 2) 570 compressMainHeader = false; 571 572 CUpdateOptions options; 573 options.Method = &methodMode; 574 options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0; 575 int level = GetLevel(); 576 options.UseFilters = level != 0 && _autoFilter; 577 options.MaxFilter = level >= 8; 578 579 options.HeaderOptions.CompressMainHeader = compressMainHeader; 580 /* 581 options.HeaderOptions.WriteCTime = Write_CTime; 582 options.HeaderOptions.WriteATime = Write_ATime; 583 options.HeaderOptions.WriteMTime = Write_MTime; 584 */ 585 586 options.NumSolidFiles = _numSolidFiles; 587 options.NumSolidBytes = _numSolidBytes; 588 options.SolidExtension = _solidExtension; 589 options.RemoveSfxBlock = _removeSfxBlock; 590 options.VolumeMode = _volumeMode; 591 592 COutArchive archive; 593 CArchiveDatabaseOut newDatabase; 594 595 CMyComPtr<ICryptoGetTextPassword> getPassword; 596 updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword); 597 598 /* 599 if (secureBlocks.Sorted.Size() > 1) 600 { 601 secureBlocks.GetReverseMap(); 602 for (int i = 0; i < updateItems.Size(); i++) 603 { 604 int &secureIndex = updateItems[i].SecureIndex; 605 secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex]; 606 } 607 } 608 */ 609 610 res = Update( 611 EXTERNAL_CODECS_VARS 612 #ifdef _7Z_VOL 613 volume ? volume->Stream: 0, 614 volume ? db : 0, 615 #else 616 _inStream, 617 db, 618 #endif 619 updateItems, 620 // treeFolders, 621 // secureBlocks, 622 archive, newDatabase, outStream, updateCallback, options 623 #ifndef _NO_CRYPTO 624 , getPassword 625 #endif 626 ); 627 628 RINOK(res); 629 630 updateItems.ClearAndFree(); 631 632 return archive.WriteDatabase(EXTERNAL_CODECS_VARS 633 newDatabase, options.HeaderMethod, options.HeaderOptions); 634 635 COM_TRY_END 636 } 637 638 static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream) 639 { 640 stream = 0; 641 int index = ParseStringToUInt32(srcString, coder); 642 if (index == 0) 643 return E_INVALIDARG; 644 srcString.Delete(0, index); 645 if (srcString[0] == 's') 646 { 647 srcString.Delete(0); 648 int index = ParseStringToUInt32(srcString, stream); 649 if (index == 0) 650 return E_INVALIDARG; 651 srcString.Delete(0, index); 652 } 653 return S_OK; 654 } 655 656 void COutHandler::InitProps() 657 { 658 CMultiMethodProps::Init(); 659 660 _removeSfxBlock = false; 661 _compressHeaders = true; 662 _encryptHeadersSpecified = false; 663 _encryptHeaders = false; 664 // _useParents = false; 665 666 Write_CTime.Init(); 667 Write_ATime.Init(); 668 Write_MTime.Init(); 669 670 _volumeMode = false; 671 InitSolid(); 672 } 673 674 HRESULT COutHandler::SetSolidFromString(const UString &s) 675 { 676 UString s2 = s; 677 s2.MakeLower_Ascii(); 678 for (unsigned i = 0; i < s2.Len();) 679 { 680 const wchar_t *start = ((const wchar_t *)s2) + i; 681 const wchar_t *end; 682 UInt64 v = ConvertStringToUInt64(start, &end); 683 if (start == end) 684 { 685 if (s2[i++] != 'e') 686 return E_INVALIDARG; 687 _solidExtension = true; 688 continue; 689 } 690 i += (int)(end - start); 691 if (i == s2.Len()) 692 return E_INVALIDARG; 693 wchar_t c = s2[i++]; 694 if (c == 'f') 695 { 696 if (v < 1) 697 v = 1; 698 _numSolidFiles = v; 699 } 700 else 701 { 702 unsigned numBits; 703 switch (c) 704 { 705 case 'b': numBits = 0; break; 706 case 'k': numBits = 10; break; 707 case 'm': numBits = 20; break; 708 case 'g': numBits = 30; break; 709 case 't': numBits = 40; break; 710 default: return E_INVALIDARG; 711 } 712 _numSolidBytes = (v << numBits); 713 _numSolidBytesDefined = true; 714 } 715 } 716 return S_OK; 717 } 718 719 HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value) 720 { 721 bool isSolid; 722 switch (value.vt) 723 { 724 case VT_EMPTY: isSolid = true; break; 725 case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break; 726 case VT_BSTR: 727 if (StringToBool(value.bstrVal, isSolid)) 728 break; 729 return SetSolidFromString(value.bstrVal); 730 default: return E_INVALIDARG; 731 } 732 if (isSolid) 733 InitSolid(); 734 else 735 _numSolidFiles = 1; 736 return S_OK; 737 } 738 739 static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) 740 { 741 RINOK(PROPVARIANT_to_bool(prop, dest.Val)); 742 dest.Def = true; 743 return S_OK; 744 } 745 746 HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) 747 { 748 UString name = nameSpec; 749 name.MakeLower_Ascii(); 750 if (name.IsEmpty()) 751 return E_INVALIDARG; 752 753 if (name[0] == L's') 754 { 755 name.Delete(0); 756 if (name.IsEmpty()) 757 return SetSolidFromPROPVARIANT(value); 758 if (value.vt != VT_EMPTY) 759 return E_INVALIDARG; 760 return SetSolidFromString(name); 761 } 762 763 UInt32 number; 764 int index = ParseStringToUInt32(name, number); 765 UString realName = name.Ptr(index); 766 if (index == 0) 767 { 768 if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); 769 if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders); 770 // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents); 771 772 if (name.IsEqualTo("hcf")) 773 { 774 bool compressHeadersFull = true; 775 RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)); 776 return compressHeadersFull ? S_OK: E_INVALIDARG; 777 } 778 779 if (name.IsEqualTo("he")) 780 { 781 RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)); 782 _encryptHeadersSpecified = true; 783 return S_OK; 784 } 785 786 if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime); 787 if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); 788 if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); 789 790 if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); 791 } 792 return CMultiMethodProps::SetProperty(name, value); 793 } 794 795 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) 796 { 797 COM_TRY_BEGIN 798 _binds.Clear(); 799 InitProps(); 800 801 for (UInt32 i = 0; i < numProps; i++) 802 { 803 UString name = names[i]; 804 name.MakeLower_Ascii(); 805 if (name.IsEmpty()) 806 return E_INVALIDARG; 807 808 const PROPVARIANT &value = values[i]; 809 810 if (name[0] == 'b') 811 { 812 if (value.vt != VT_EMPTY) 813 return E_INVALIDARG; 814 name.Delete(0); 815 CBind bind; 816 RINOK(GetBindInfoPart(name, bind.OutCoder, bind.OutStream)); 817 if (name[0] != ':') 818 return E_INVALIDARG; 819 name.Delete(0); 820 RINOK(GetBindInfoPart(name, bind.InCoder, bind.InStream)); 821 if (!name.IsEmpty()) 822 return E_INVALIDARG; 823 _binds.Add(bind); 824 continue; 825 } 826 827 RINOK(SetProperty(name, value)); 828 } 829 830 unsigned numEmptyMethods = GetNumEmptyMethods(); 831 if (numEmptyMethods > 0) 832 { 833 unsigned k; 834 for (k = 0; k < _binds.Size(); k++) 835 { 836 const CBind &bind = _binds[k]; 837 if (bind.InCoder < (UInt32)numEmptyMethods || 838 bind.OutCoder < (UInt32)numEmptyMethods) 839 return E_INVALIDARG; 840 } 841 for (k = 0; k < _binds.Size(); k++) 842 { 843 CBind &bind = _binds[k]; 844 bind.InCoder -= (UInt32)numEmptyMethods; 845 bind.OutCoder -= (UInt32)numEmptyMethods; 846 } 847 _methods.DeleteFrontal(numEmptyMethods); 848 } 849 850 AddDefaultMethod(); 851 852 if (!_filterMethod.MethodName.IsEmpty()) 853 { 854 FOR_VECTOR (k, _binds) 855 { 856 CBind &bind = _binds[k]; 857 bind.InCoder++; 858 bind.OutCoder++; 859 } 860 _methods.Insert(0, _filterMethod); 861 } 862 863 FOR_VECTOR (k, _binds) 864 { 865 const CBind &bind = _binds[k]; 866 if (bind.InCoder >= (UInt32)_methods.Size() || 867 bind.OutCoder >= (UInt32)_methods.Size()) 868 return E_INVALIDARG; 869 } 870 871 return S_OK; 872 COM_TRY_END 873 } 874 875 }} 876