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