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