7zHandlerOut.cpp (25241B)
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 /* 271 CMyComPtr<IArchiveGetRawProps> getRawProps; 272 updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps); 273 274 CUniqBlocks secureBlocks; 275 secureBlocks.AddUniq(NULL, 0); 276 277 CObjectVector<CTreeFolder> treeFolders; 278 { 279 CTreeFolder folder; 280 folder.Parent = -1; 281 treeFolders.Add(folder); 282 } 283 */ 284 285 CObjectVector<CUpdateItem> updateItems; 286 287 bool need_CTime = (Write_CTime.Def && Write_CTime.Val); 288 bool need_ATime = (Write_ATime.Def && Write_ATime.Val); 289 bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def); 290 bool need_Attrib = (Write_Attrib.Def && Write_Attrib.Val || !Write_Attrib.Def); 291 292 if (db && !db->Files.IsEmpty()) 293 { 294 if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty(); 295 if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty(); 296 if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty(); 297 if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty(); 298 } 299 300 // UString s; 301 UString name; 302 303 for (UInt32 i = 0; i < numItems; i++) 304 { 305 Int32 newData, newProps; 306 UInt32 indexInArchive; 307 if (!updateCallback) 308 return E_FAIL; 309 RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive)); 310 CUpdateItem ui; 311 ui.NewProps = IntToBool(newProps); 312 ui.NewData = IntToBool(newData); 313 ui.IndexInArchive = indexInArchive; 314 ui.IndexInClient = i; 315 ui.IsAnti = false; 316 ui.Size = 0; 317 318 name.Empty(); 319 // bool isAltStream = false; 320 if (ui.IndexInArchive != -1) 321 { 322 if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size()) 323 return E_INVALIDARG; 324 const CFileItem &fi = db->Files[ui.IndexInArchive]; 325 if (!ui.NewProps) 326 { 327 _db.GetPath(ui.IndexInArchive, name); 328 } 329 ui.IsDir = fi.IsDir; 330 ui.Size = fi.Size; 331 // isAltStream = fi.IsAltStream; 332 ui.IsAnti = db->IsItemAnti(ui.IndexInArchive); 333 334 if (!ui.NewProps) 335 { 336 ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime); 337 ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime); 338 ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime); 339 } 340 } 341 342 if (ui.NewProps) 343 { 344 bool folderStatusIsDefined; 345 if (need_Attrib) 346 { 347 NCOM::CPropVariant prop; 348 RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop)); 349 if (prop.vt == VT_EMPTY) 350 ui.AttribDefined = false; 351 else if (prop.vt != VT_UI4) 352 return E_INVALIDARG; 353 else 354 { 355 ui.Attrib = prop.ulVal; 356 ui.AttribDefined = true; 357 } 358 } 359 360 // we need MTime to sort files. 361 if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined)); 362 if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined)); 363 if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined)); 364 365 /* 366 if (getRawProps) 367 { 368 const void *data; 369 UInt32 dataSize; 370 UInt32 propType; 371 372 getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType); 373 if (dataSize != 0 && propType != NPropDataType::kRaw) 374 return E_FAIL; 375 ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize); 376 } 377 */ 378 379 { 380 NCOM::CPropVariant prop; 381 RINOK(updateCallback->GetProperty(i, kpidPath, &prop)); 382 if (prop.vt == VT_EMPTY) 383 { 384 } 385 else if (prop.vt != VT_BSTR) 386 return E_INVALIDARG; 387 else 388 { 389 name = prop.bstrVal; 390 NItemName::ReplaceSlashes_OsToUnix(name); 391 } 392 } 393 { 394 NCOM::CPropVariant prop; 395 RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop)); 396 if (prop.vt == VT_EMPTY) 397 folderStatusIsDefined = false; 398 else if (prop.vt != VT_BOOL) 399 return E_INVALIDARG; 400 else 401 { 402 ui.IsDir = (prop.boolVal != VARIANT_FALSE); 403 folderStatusIsDefined = true; 404 } 405 } 406 407 { 408 NCOM::CPropVariant prop; 409 RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop)); 410 if (prop.vt == VT_EMPTY) 411 ui.IsAnti = false; 412 else if (prop.vt != VT_BOOL) 413 return E_INVALIDARG; 414 else 415 ui.IsAnti = (prop.boolVal != VARIANT_FALSE); 416 } 417 418 /* 419 { 420 NCOM::CPropVariant prop; 421 RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop)); 422 if (prop.vt == VT_EMPTY) 423 isAltStream = false; 424 else if (prop.vt != VT_BOOL) 425 return E_INVALIDARG; 426 else 427 isAltStream = (prop.boolVal != VARIANT_FALSE); 428 } 429 */ 430 431 if (ui.IsAnti) 432 { 433 ui.AttribDefined = false; 434 435 ui.CTimeDefined = false; 436 ui.ATimeDefined = false; 437 ui.MTimeDefined = false; 438 439 ui.Size = 0; 440 } 441 442 if (!folderStatusIsDefined && ui.AttribDefined) 443 ui.SetDirStatusFromAttrib(); 444 } 445 else 446 { 447 /* 448 if (_db.SecureIDs.IsEmpty()) 449 ui.SecureIndex = secureBlocks.AddUniq(NULL, 0); 450 else 451 { 452 int id = _db.SecureIDs[ui.IndexInArchive]; 453 size_t offs = _db.SecureOffsets[id]; 454 size_t size = _db.SecureOffsets[id + 1] - offs; 455 ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size); 456 } 457 */ 458 } 459 460 /* 461 { 462 int folderIndex = 0; 463 if (_useParents) 464 { 465 int j; 466 s.Empty(); 467 for (j = 0; j < name.Len(); j++) 468 { 469 wchar_t c = name[j]; 470 if (IsCharDirLimiter(c)) 471 { 472 folderIndex = AddFolder(treeFolders, folderIndex, s); 473 s.Empty(); 474 continue; 475 } 476 s += c; 477 } 478 if (isAltStream) 479 { 480 int colonPos = s.Find(':'); 481 if (colonPos < 0) 482 { 483 // isAltStream = false; 484 return E_INVALIDARG; 485 } 486 UString mainName = s.Left(colonPos); 487 int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName); 488 if (treeFolders[newFolderIndex].UpdateItemIndex < 0) 489 { 490 for (int j = updateItems.Size() - 1; j >= 0; j--) 491 { 492 CUpdateItem &ui2 = updateItems[j]; 493 if (ui2.ParentFolderIndex == folderIndex 494 && ui2.Name == mainName) 495 { 496 ui2.TreeFolderIndex = newFolderIndex; 497 treeFolders[newFolderIndex].UpdateItemIndex = j; 498 } 499 } 500 } 501 folderIndex = newFolderIndex; 502 s.Delete(0, colonPos + 1); 503 } 504 ui.Name = s; 505 } 506 else 507 ui.Name = name; 508 ui.IsAltStream = isAltStream; 509 ui.ParentFolderIndex = folderIndex; 510 ui.TreeFolderIndex = -1; 511 if (ui.IsDir && !s.IsEmpty()) 512 { 513 ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s); 514 treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size(); 515 } 516 } 517 */ 518 ui.Name = name; 519 520 if (ui.NewData) 521 { 522 ui.Size = 0; 523 if (!ui.IsDir) 524 { 525 NCOM::CPropVariant prop; 526 RINOK(updateCallback->GetProperty(i, kpidSize, &prop)); 527 if (prop.vt != VT_UI8) 528 return E_INVALIDARG; 529 ui.Size = (UInt64)prop.uhVal.QuadPart; 530 if (ui.Size != 0 && ui.IsAnti) 531 return E_INVALIDARG; 532 } 533 } 534 535 updateItems.Add(ui); 536 } 537 538 /* 539 FillSortIndex(treeFolders, 0, 0); 540 for (i = 0; i < (UInt32)updateItems.Size(); i++) 541 { 542 CUpdateItem &ui = updateItems[i]; 543 ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex; 544 ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd; 545 } 546 */ 547 548 CCompressionMethodMode methodMode, headerMethod; 549 550 HRESULT res = SetMainMethod(methodMode 551 #ifndef _7ZIP_ST 552 , _numThreads 553 #endif 554 ); 555 RINOK(res); 556 557 RINOK(SetHeaderMethod(headerMethod)); 558 559 #ifndef _7ZIP_ST 560 methodMode.NumThreads = _numThreads; 561 methodMode.MultiThreadMixer = _useMultiThreadMixer; 562 headerMethod.NumThreads = 1; 563 headerMethod.MultiThreadMixer = _useMultiThreadMixer; 564 #endif 565 566 CMyComPtr<ICryptoGetTextPassword2> getPassword2; 567 updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2); 568 569 methodMode.PasswordIsDefined = false; 570 methodMode.Password.Empty(); 571 if (getPassword2) 572 { 573 CMyComBSTR password; 574 Int32 passwordIsDefined; 575 RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password)); 576 methodMode.PasswordIsDefined = IntToBool(passwordIsDefined); 577 if (methodMode.PasswordIsDefined && password) 578 methodMode.Password = password; 579 } 580 581 bool compressMainHeader = _compressHeaders; // check it 582 583 bool encryptHeaders = false; 584 585 #ifndef _NO_CRYPTO 586 if (!methodMode.PasswordIsDefined && _passwordIsDefined) 587 { 588 // if header is compressed, we use that password for updated archive 589 methodMode.PasswordIsDefined = true; 590 methodMode.Password = _password; 591 } 592 #endif 593 594 if (methodMode.PasswordIsDefined) 595 { 596 if (_encryptHeadersSpecified) 597 encryptHeaders = _encryptHeaders; 598 #ifndef _NO_CRYPTO 599 else 600 encryptHeaders = _passwordIsDefined; 601 #endif 602 compressMainHeader = true; 603 if (encryptHeaders) 604 { 605 headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined; 606 headerMethod.Password = methodMode.Password; 607 } 608 } 609 610 if (numItems < 2) 611 compressMainHeader = false; 612 613 int level = GetLevel(); 614 615 CUpdateOptions options; 616 options.Method = &methodMode; 617 options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL; 618 options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted); 619 options.MaxFilter = (level >= 8); 620 options.AnalysisLevel = GetAnalysisLevel(); 621 622 options.HeaderOptions.CompressMainHeader = compressMainHeader; 623 /* 624 options.HeaderOptions.WriteCTime = Write_CTime; 625 options.HeaderOptions.WriteATime = Write_ATime; 626 options.HeaderOptions.WriteMTime = Write_MTime; 627 options.HeaderOptions.WriteAttrib = Write_Attrib; 628 */ 629 630 options.NumSolidFiles = _numSolidFiles; 631 options.NumSolidBytes = _numSolidBytes; 632 options.SolidExtension = _solidExtension; 633 options.UseTypeSorting = _useTypeSorting; 634 635 options.RemoveSfxBlock = _removeSfxBlock; 636 // options.VolumeMode = _volumeMode; 637 638 options.MultiThreadMixer = _useMultiThreadMixer; 639 640 COutArchive archive; 641 CArchiveDatabaseOut newDatabase; 642 643 CMyComPtr<ICryptoGetTextPassword> getPassword; 644 updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword); 645 646 /* 647 if (secureBlocks.Sorted.Size() > 1) 648 { 649 secureBlocks.GetReverseMap(); 650 for (int i = 0; i < updateItems.Size(); i++) 651 { 652 int &secureIndex = updateItems[i].SecureIndex; 653 secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex]; 654 } 655 } 656 */ 657 658 res = Update( 659 EXTERNAL_CODECS_VARS 660 #ifdef _7Z_VOL 661 volume ? volume->Stream: 0, 662 volume ? db : 0, 663 #else 664 _inStream, 665 db, 666 #endif 667 updateItems, 668 // treeFolders, 669 // secureBlocks, 670 archive, newDatabase, outStream, updateCallback, options 671 #ifndef _NO_CRYPTO 672 , getPassword 673 #endif 674 ); 675 676 RINOK(res); 677 678 updateItems.ClearAndFree(); 679 680 return archive.WriteDatabase(EXTERNAL_CODECS_VARS 681 newDatabase, options.HeaderMethod, options.HeaderOptions); 682 683 COM_TRY_END 684 } 685 686 static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream) 687 { 688 stream = 0; 689 { 690 unsigned index = ParseStringToUInt32(srcString, coder); 691 if (index == 0) 692 return E_INVALIDARG; 693 srcString.DeleteFrontal(index); 694 } 695 if (srcString[0] == 's') 696 { 697 srcString.Delete(0); 698 unsigned index = ParseStringToUInt32(srcString, stream); 699 if (index == 0) 700 return E_INVALIDARG; 701 srcString.DeleteFrontal(index); 702 } 703 return S_OK; 704 } 705 706 void COutHandler::InitProps7z() 707 { 708 _removeSfxBlock = false; 709 _compressHeaders = true; 710 _encryptHeadersSpecified = false; 711 _encryptHeaders = false; 712 // _useParents = false; 713 714 Write_CTime.Init(); 715 Write_ATime.Init(); 716 Write_MTime.Init(); 717 Write_Attrib.Init(); 718 719 _useMultiThreadMixer = true; 720 721 // _volumeMode = false; 722 723 InitSolid(); 724 _useTypeSorting = false; 725 } 726 727 void COutHandler::InitProps() 728 { 729 CMultiMethodProps::Init(); 730 InitProps7z(); 731 } 732 733 734 735 HRESULT COutHandler::SetSolidFromString(const UString &s) 736 { 737 UString s2 = s; 738 s2.MakeLower_Ascii(); 739 for (unsigned i = 0; i < s2.Len();) 740 { 741 const wchar_t *start = ((const wchar_t *)s2) + i; 742 const wchar_t *end; 743 UInt64 v = ConvertStringToUInt64(start, &end); 744 if (start == end) 745 { 746 if (s2[i++] != 'e') 747 return E_INVALIDARG; 748 _solidExtension = true; 749 continue; 750 } 751 i += (int)(end - start); 752 if (i == s2.Len()) 753 return E_INVALIDARG; 754 wchar_t c = s2[i++]; 755 if (c == 'f') 756 { 757 if (v < 1) 758 v = 1; 759 _numSolidFiles = v; 760 } 761 else 762 { 763 unsigned numBits; 764 switch (c) 765 { 766 case 'b': numBits = 0; break; 767 case 'k': numBits = 10; break; 768 case 'm': numBits = 20; break; 769 case 'g': numBits = 30; break; 770 case 't': numBits = 40; break; 771 default: return E_INVALIDARG; 772 } 773 _numSolidBytes = (v << numBits); 774 _numSolidBytesDefined = true; 775 /* 776 if (_numSolidBytes == 0) 777 _numSolidFiles = 1; 778 */ 779 } 780 } 781 return S_OK; 782 } 783 784 HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value) 785 { 786 bool isSolid; 787 switch (value.vt) 788 { 789 case VT_EMPTY: isSolid = true; break; 790 case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break; 791 case VT_BSTR: 792 if (StringToBool(value.bstrVal, isSolid)) 793 break; 794 return SetSolidFromString(value.bstrVal); 795 default: return E_INVALIDARG; 796 } 797 if (isSolid) 798 InitSolid(); 799 else 800 _numSolidFiles = 1; 801 return S_OK; 802 } 803 804 static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest) 805 { 806 RINOK(PROPVARIANT_to_bool(prop, dest.Val)); 807 dest.Def = true; 808 return S_OK; 809 } 810 811 HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value) 812 { 813 UString name = nameSpec; 814 name.MakeLower_Ascii(); 815 if (name.IsEmpty()) 816 return E_INVALIDARG; 817 818 if (name[0] == L's') 819 { 820 name.Delete(0); 821 if (name.IsEmpty()) 822 return SetSolidFromPROPVARIANT(value); 823 if (value.vt != VT_EMPTY) 824 return E_INVALIDARG; 825 return SetSolidFromString(name); 826 } 827 828 UInt32 number; 829 int index = ParseStringToUInt32(name, number); 830 // UString realName = name.Ptr(index); 831 if (index == 0) 832 { 833 if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock); 834 if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders); 835 // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents); 836 837 if (name.IsEqualTo("hcf")) 838 { 839 bool compressHeadersFull = true; 840 RINOK(PROPVARIANT_to_bool(value, compressHeadersFull)); 841 return compressHeadersFull ? S_OK: E_INVALIDARG; 842 } 843 844 if (name.IsEqualTo("he")) 845 { 846 RINOK(PROPVARIANT_to_bool(value, _encryptHeaders)); 847 _encryptHeadersSpecified = true; 848 return S_OK; 849 } 850 851 if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime); 852 if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime); 853 if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime); 854 855 if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib); 856 857 if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer); 858 859 if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting); 860 861 // if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode); 862 } 863 return CMultiMethodProps::SetProperty(name, value); 864 } 865 866 STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) 867 { 868 COM_TRY_BEGIN 869 _bonds.Clear(); 870 InitProps(); 871 872 for (UInt32 i = 0; i < numProps; i++) 873 { 874 UString name = names[i]; 875 name.MakeLower_Ascii(); 876 if (name.IsEmpty()) 877 return E_INVALIDARG; 878 879 const PROPVARIANT &value = values[i]; 880 881 if (name[0] == 'b') 882 { 883 if (value.vt != VT_EMPTY) 884 return E_INVALIDARG; 885 name.Delete(0); 886 887 CBond2 bond; 888 RINOK(ParseBond(name, bond.OutCoder, bond.OutStream)); 889 if (name[0] != ':') 890 return E_INVALIDARG; 891 name.Delete(0); 892 UInt32 inStream = 0; 893 RINOK(ParseBond(name, bond.InCoder, inStream)); 894 if (inStream != 0) 895 return E_INVALIDARG; 896 if (!name.IsEmpty()) 897 return E_INVALIDARG; 898 _bonds.Add(bond); 899 continue; 900 } 901 902 RINOK(SetProperty(name, value)); 903 } 904 905 unsigned numEmptyMethods = GetNumEmptyMethods(); 906 if (numEmptyMethods > 0) 907 { 908 unsigned k; 909 for (k = 0; k < _bonds.Size(); k++) 910 { 911 const CBond2 &bond = _bonds[k]; 912 if (bond.InCoder < (UInt32)numEmptyMethods || 913 bond.OutCoder < (UInt32)numEmptyMethods) 914 return E_INVALIDARG; 915 } 916 for (k = 0; k < _bonds.Size(); k++) 917 { 918 CBond2 &bond = _bonds[k]; 919 bond.InCoder -= (UInt32)numEmptyMethods; 920 bond.OutCoder -= (UInt32)numEmptyMethods; 921 } 922 _methods.DeleteFrontal(numEmptyMethods); 923 } 924 925 FOR_VECTOR (k, _bonds) 926 { 927 const CBond2 &bond = _bonds[k]; 928 if (bond.InCoder >= (UInt32)_methods.Size() || 929 bond.OutCoder >= (UInt32)_methods.Size()) 930 return E_INVALIDARG; 931 } 932 933 return S_OK; 934 COM_TRY_END 935 } 936 937 }} 938 939 #endif