1// 7zUpdate.cpp 2 3#include "StdAfx.h" 4 5#include "../../../../C/CpuArch.h" 6 7#include "../../../Common/MyLinux.h" 8#include "../../../Common/StringToInt.h" 9#include "../../../Common/Wildcard.h" 10 11#include "../../Common/CreateCoder.h" 12#include "../../Common/LimitedStreams.h" 13#include "../../Common/ProgressUtils.h" 14 15#include "../../Compress/CopyCoder.h" 16 17#include "../Common/ItemNameUtils.h" 18 19#include "7zDecode.h" 20#include "7zEncode.h" 21#include "7zFolderInStream.h" 22#include "7zHandler.h" 23#include "7zOut.h" 24#include "7zUpdate.h" 25 26namespace NArchive { 27namespace N7z { 28 29#define k_X86 k_BCJ 30 31struct CFilterMode 32{ 33 UInt32 Id; 34 UInt32 Delta; // required File Size alignment, if Id is not k_Delta. 35 // (Delta == 0) means unknown alignment 36 UInt32 Offset; // for k_ARM64 37 // UInt32 AlignSizeOpt; // for k_ARM64 38 39 CFilterMode(): 40 Id(0), 41 Delta(0), 42 Offset(0) 43 // , AlignSizeOpt(0) 44 {} 45 46 void ClearFilterMode() 47 { 48 Id = 0; 49 Delta = 0; 50 Offset = 0; 51 // AlignSizeOpt = 0; 52 } 53 54 // it sets Delta as Align value, if Id is exe filter 55 // in another cases it sets Delta = 0, that 56 void SetDelta() 57 { 58 if (Id == k_IA64) 59 Delta = 16; 60 else if (Id == k_ARM64 || Id == k_ARM || Id == k_PPC || Id == k_SPARC) 61 Delta = 4; 62 else if (Id == k_ARMT) 63 Delta = 2; 64 else if (Id == k_BCJ || Id == k_BCJ2) 65 Delta = 1; // do we need it? 66 else 67 Delta = 0; 68 } 69}; 70 71 72/* ---------- PE ---------- */ 73 74#define MZ_SIG 0x5A4D 75 76#define PE_SIG 0x00004550 77#define PE_OptHeader_Magic_32 0x10B 78#define PE_OptHeader_Magic_64 0x20B 79// #define PE_SectHeaderSize 40 80// #define PE_SECT_EXECUTE 0x20000000 81 82static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode) 83{ 84 if (size < 512 || GetUi16(buf) != MZ_SIG) 85 return 0; 86 87 const Byte *p; 88 UInt32 peOffset, optHeaderSize, filterId; 89 90 peOffset = GetUi32(buf + 0x3C); 91 if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0) 92 return 0; 93 p = buf + peOffset; 94 if (GetUi32(p) != PE_SIG) 95 return 0; 96 p += 4; 97 98 switch (GetUi16(p)) 99 { 100 case 0x014C: 101 case 0x8664: filterId = k_X86; break; 102 case 0xAA64: filterId = k_ARM64; break; 103 104 /* 105 IMAGE_FILE_MACHINE_ARM 0x01C0 // ARM LE 106 IMAGE_FILE_MACHINE_THUMB 0x01C2 // ARM Thumb / Thumb-2 LE 107 IMAGE_FILE_MACHINE_ARMNT 0x01C4 // ARM Thumb-2, LE 108 Note: We use ARM filter for 0x01C2. (WinCE 5 - 0x01C2) files mostly contain ARM code (not Thumb/Thumb-2). 109 */ 110 111 case 0x01C0: // WinCE old 112 case 0x01C2: filterId = k_ARM; break; // WinCE new 113 case 0x01C4: filterId = k_ARMT; break; // WinRT 114 115 case 0x0200: filterId = k_IA64; break; 116 default: return 0; 117 } 118 119 // const UInt32 numSections = GetUi16(p + 2); 120 optHeaderSize = GetUi16(p + 16); 121 if (optHeaderSize > (1 << 10)) 122 return 0; 123 124 p += 20; /* headerSize */ 125 126 switch (GetUi16(p)) 127 { 128 case PE_OptHeader_Magic_32: 129 case PE_OptHeader_Magic_64: 130 break; 131 default: 132 return 0; 133 } 134 135 /* 136 // Windows exe file sizes are not aligned for 4 KiB. 137 // So we can't use (CFilterMode::Offset != 0) in solid archives. 138 // So we just don't set Offset here. 139#define NUM_SCAN_SECTIONS_MAX (1 << 6) 140#define EXE_SECTION_OFFSET_MAX (1 << 27) 141#define EXE_SECTION_SIZE_MIN (1 << 8) 142#define EXE_SECTION_SIZE_MAX (1 << 27) 143#define PE_SectHeaderSize 40 144#define PE_SECT_EXECUTE 0x20000000 145 146 if (numSections > NUM_SCAN_SECTIONS_MAX) 147 return 0; 148 149 p += optHeaderSize; 150 // UInt32 numExeSections = 0; 151 // bool execute_finded = false; 152 // UInt32 sect_va = 0; 153 // UInt32 sect_size = 0; 154 // UInt32 sect_offset = 0; 155 156 for (UInt32 i = 0; i < numSections 157 // && numExeSections < numSectionsMax 158 ; i++, p += PE_SectHeaderSize) 159 { 160 UInt32 characts, rawSize, offset; 161 if ((UInt32)(p - buf) + PE_SectHeaderSize > size) 162 return 0; 163 rawSize = GetUi32(p + 16); 164 offset = GetUi32(p + 20); 165 characts = GetUi32(p + 36); 166 if (rawSize >= EXE_SECTION_SIZE_MIN && 167 rawSize <= EXE_SECTION_SIZE_MAX && 168 offset <= EXE_SECTION_OFFSET_MAX && 169 // offset < limit && 170 offset > 0) 171 { 172 if ((characts & PE_SECT_EXECUTE) != 0) 173 { 174 // execute_finded = true; 175 // sect_va = GetUi32(p + 12); 176 // sect_size = rawSize; 177 // sect_offset = offset; 178 break; 179 } 180 } 181 } 182 183 filterMode->Offset = 0; 184 if (filterId == k_ARM64) 185 { 186 // filterMode->AlignSizeOpt = (1 << 12); 187 // const UInt32 offs = (sect_va - sect_offset) & 0xFFF; 188 // if (offs != 0) 189 // filterMode->Offset = offs; // change it 190 } 191 */ 192 filterMode->Id = filterId; 193 return 1; 194} 195 196 197/* ---------- ELF ---------- */ 198 199#define ELF_SIG 0x464C457F 200 201#define ELF_CLASS_32 1 202#define ELF_CLASS_64 2 203 204#define ELF_DATA_2LSB 1 205#define ELF_DATA_2MSB 2 206 207static UInt16 Get16(const Byte *p, BoolInt be) { if (be) return (UInt16)GetBe16(p); return (UInt16)GetUi16(p); } 208static UInt32 Get32(const Byte *p, BoolInt be) { if (be) return GetBe32(p); return GetUi32(p); } 209// static UInt64 Get64(const Byte *p, BoolInt be) { if (be) return GetBe64(p); return GetUi64(p); } 210 211static int Parse_ELF(const Byte *buf, size_t size, CFilterMode *filterMode) 212{ 213 BoolInt /* is32, */ be; 214 UInt32 filterId; 215 216 if (size < 512 || buf[6] != 1) /* ver */ 217 return 0; 218 219 if (GetUi32(buf) != ELF_SIG) 220 return 0; 221 222 switch (buf[4]) 223 { 224 case ELF_CLASS_32: /* is32 = True; */ break; 225 case ELF_CLASS_64: /* is32 = False; */ break; 226 default: return 0; 227 } 228 229 switch (buf[5]) 230 { 231 case ELF_DATA_2LSB: be = False; break; 232 case ELF_DATA_2MSB: be = True; break; 233 default: return 0; 234 } 235 236 switch (Get16(buf + 0x12, be)) 237 { 238 case 3: 239 case 6: 240 case 62: filterId = k_X86; break; 241 case 2: 242 case 18: 243 case 43: filterId = k_SPARC; break; 244 case 20: 245 case 21: if (!be) return 0; filterId = k_PPC; break; 246 case 40: if ( be) return 0; filterId = k_ARM; break; 247 case 183: if (be) return 0; filterId = k_ARM64; break; 248 249 /* Some IA-64 ELF executables have size that is not aligned for 16 bytes. 250 So we don't use IA-64 filter for IA-64 ELF */ 251 // case 50: if ( be) return 0; filterId = k_IA64; break; 252 253 default: return 0; 254 } 255 256 filterMode->Id = filterId; 257 return 1; 258} 259 260 261 262/* ---------- Mach-O ---------- */ 263 264#define MACH_SIG_BE_32 0xCEFAEDFE 265#define MACH_SIG_BE_64 0xCFFAEDFE 266#define MACH_SIG_LE_32 0xFEEDFACE 267#define MACH_SIG_LE_64 0xFEEDFACF 268 269#define MACH_ARCH_ABI64 (1 << 24) 270#define MACH_MACHINE_386 7 271#define MACH_MACHINE_ARM 12 272#define MACH_MACHINE_SPARC 14 273#define MACH_MACHINE_PPC 18 274#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC) 275#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386) 276#define MACH_MACHINE_ARM64 (MACH_ARCH_ABI64 | MACH_MACHINE_ARM) 277 278static unsigned Parse_MACH(const Byte *buf, size_t size, CFilterMode *filterMode) 279{ 280 UInt32 filterId, numCommands, commandsSize; 281 282 if (size < 512) 283 return 0; 284 285 BoolInt /* mode64, */ be; 286 switch (GetUi32(buf)) 287 { 288 case MACH_SIG_BE_32: /* mode64 = False; */ be = True; break; 289 case MACH_SIG_BE_64: /* mode64 = True; */ be = True; break; 290 case MACH_SIG_LE_32: /* mode64 = False; */ be = False; break; 291 case MACH_SIG_LE_64: /* mode64 = True; */ be = False; break; 292 default: return 0; 293 } 294 295 switch (Get32(buf + 4, be)) 296 { 297 case MACH_MACHINE_386: 298 case MACH_MACHINE_AMD64: filterId = k_X86; break; 299 case MACH_MACHINE_ARM: if ( be) return 0; filterId = k_ARM; break; 300 case MACH_MACHINE_SPARC: if (!be) return 0; filterId = k_SPARC; break; 301 case MACH_MACHINE_PPC: 302 case MACH_MACHINE_PPC64: if (!be) return 0; filterId = k_PPC; break; 303 case MACH_MACHINE_ARM64: if ( be) return 0; filterId = k_ARM64; break; 304 default: return 0; 305 } 306 307 numCommands = Get32(buf + 0x10, be); 308 commandsSize = Get32(buf + 0x14, be); 309 310 if (commandsSize > (1 << 24) || numCommands > (1 << 18)) 311 return 0; 312 313 filterMode->Id = filterId; 314 return 1; 315} 316 317 318/* ---------- WAV ---------- */ 319 320#define WAV_SUBCHUNK_fmt 0x20746D66 321#define WAV_SUBCHUNK_data 0x61746164 322 323#define RIFF_SIG 0x46464952 324 325static BoolInt Parse_WAV(const Byte *buf, size_t size, CFilterMode *filterMode) 326{ 327 UInt32 subChunkSize, pos; 328 if (size < 0x2C) 329 return False; 330 331 if (GetUi32(buf + 0) != RIFF_SIG || 332 GetUi32(buf + 8) != 0x45564157 || // WAVE 333 GetUi32(buf + 0xC) != WAV_SUBCHUNK_fmt) 334 return False; 335 subChunkSize = GetUi32(buf + 0x10); 336 /* [0x14 = format] = 1 (PCM) */ 337 if (subChunkSize < 0x10 || subChunkSize > 0x12 || GetUi16(buf + 0x14) != 1) 338 return False; 339 340 const unsigned numChannels = GetUi16(buf + 0x16); 341 const unsigned bitsPerSample = GetUi16(buf + 0x22); 342 if ((bitsPerSample & 0x7) != 0) 343 return False; 344 const UInt32 delta = (UInt32)numChannels * (bitsPerSample >> 3); 345 if (delta == 0 || delta > 256) 346 return False; 347 348 pos = 0x14 + subChunkSize; 349 350 const int kNumSubChunksTests = 10; 351 // Do we need to scan more than 3 sub-chunks? 352 for (int i = 0; i < kNumSubChunksTests; i++) 353 { 354 if (pos + 8 > size) 355 return False; 356 subChunkSize = GetUi32(buf + pos + 4); 357 if (GetUi32(buf + pos) == WAV_SUBCHUNK_data) 358 { 359 filterMode->Id = k_Delta; 360 filterMode->Delta = delta; 361 return True; 362 } 363 if (subChunkSize > (1 << 16)) 364 return False; 365 pos += subChunkSize + 8; 366 } 367 return False; 368} 369 370 371/* 372 filterMode->Delta will be set as: 373 = delta value : [1, 256] : for k_Delta 374 = 0 for another filters (branch filters) 375*/ 376static BoolInt ParseFile(const Byte *buf, size_t size, CFilterMode *filterMode) 377{ 378 filterMode->ClearFilterMode(); 379 380 if (Parse_EXE(buf, size, filterMode)) return True; 381 if (Parse_ELF(buf, size, filterMode)) return True; 382 if (Parse_MACH(buf, size, filterMode)) return True; 383 return Parse_WAV(buf, size, filterMode); 384} 385 386 387 388 389struct CFilterMode2: public CFilterMode 390{ 391 bool Encrypted; 392 unsigned GroupIndex; 393 394 CFilterMode2(): Encrypted(false) {} 395 396 int Compare(const CFilterMode2 &m) const 397 { 398 if (!Encrypted) 399 { 400 if (m.Encrypted) 401 return -1; 402 } 403 else if (!m.Encrypted) 404 return 1; 405 406 const UInt32 id1 = Id; 407 const UInt32 id2 = m.Id; 408 /* 409 // we can change the order to place k_ARM64 files close to another exe files 410 if (id1 <= k_SPARC && 411 id2 <= k_SPARC) 412 { 413 #define k_ARM64_FOR_SORT 0x3030901 414 if (id1 == k_ARM64) id1 = k_ARM64_FOR_SORT; 415 if (id2 == k_ARM64) id2 = k_ARM64_FOR_SORT; 416 } 417 */ 418 if (id1 < id2) return -1; 419 if (id1 > id2) return 1; 420 421 if (Delta < m.Delta) return -1; 422 if (Delta > m.Delta) return 1; 423 424 if (Offset < m.Offset) return -1; 425 if (Offset > m.Offset) return 1; 426 427 /* we don't go here, because GetGroup() 428 and operator ==(const CFilterMode2 &m) 429 add only unique CFilterMode2:: { Id, Delta, Offset, Encrypted } items. 430 */ 431 /* 432 if (GroupIndex < m.GroupIndex) return -1; 433 if (GroupIndex > m.GroupIndex) return 1; 434 */ 435 return 0; 436 } 437 438 bool operator ==(const CFilterMode2 &m) const 439 { 440 return Id == m.Id 441 && Delta == m.Delta 442 && Offset == m.Offset 443 && Encrypted == m.Encrypted; 444 } 445}; 446 447static unsigned GetGroup(CRecordVector<CFilterMode2> &filters, const CFilterMode2 &m) 448{ 449 unsigned i; 450 for (i = 0; i < filters.Size(); i++) 451 { 452 const CFilterMode2 &m2 = filters[i]; 453 if (m == m2) 454 return i; 455 /* 456 if (m.Encrypted != m2.Encrypted) 457 { 458 if (!m.Encrypted) 459 break; 460 continue; 461 } 462 463 if (m.Id < m2.Id) break; 464 if (m.Id != m2.Id) continue; 465 466 if (m.Delta < m2.Delta) break; 467 if (m.Delta != m2.Delta) continue; 468 */ 469 } 470 // filters.Insert(i, m); 471 // return i; 472 return filters.Add(m); 473} 474 475static inline bool Is86Filter(CMethodId m) 476{ 477 return (m == k_BCJ || m == k_BCJ2); 478} 479 480static inline bool IsExeFilter(CMethodId m) 481{ 482 switch (m) 483 { 484 case k_ARM64: 485 case k_BCJ: 486 case k_BCJ2: 487 case k_ARM: 488 case k_ARMT: 489 case k_PPC: 490 case k_SPARC: 491 case k_IA64: 492 return true; 493 } 494 return false; 495} 496 497static unsigned Get_FilterGroup_for_Folder( 498 CRecordVector<CFilterMode2> &filters, const CFolderEx &f, bool extractFilter) 499{ 500 CFilterMode2 m; 501 // m.Id = 0; 502 // m.Delta = 0; 503 // m.Offset = 0; 504 m.Encrypted = f.IsEncrypted(); 505 506 if (extractFilter) 507 { 508 const CCoderInfo &coder = f.Coders[f.UnpackCoder]; 509 510 if (coder.MethodID == k_Delta) 511 { 512 if (coder.Props.Size() == 1) 513 { 514 m.Delta = (unsigned)coder.Props[0] + 1; 515 m.Id = k_Delta; 516 } 517 } 518 else if (IsExeFilter(coder.MethodID)) 519 { 520 m.Id = (UInt32)coder.MethodID; 521 if (m.Id == k_BCJ2) 522 m.Id = k_BCJ; 523 m.SetDelta(); 524 if (m.Id == k_ARM64) 525 if (coder.Props.Size() == 4) 526 m.Offset = GetUi32(coder.Props); 527 } 528 } 529 530 return GetGroup(filters, m); 531} 532 533 534 535 536static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream, 537 UInt64 position, UInt64 size, ICompressProgressInfo *progress) 538{ 539 RINOK(InStream_SeekSet(inStream, position)) 540 CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; 541 CMyComPtr<ISequentialInStream> inStreamLimited(streamSpec); 542 streamSpec->SetStream(inStream); 543 streamSpec->Init(size); 544 545 NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder; 546 CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec; 547 RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress)) 548 return (copyCoderSpec->TotalSize == size ? S_OK : E_FAIL); 549} 550 551/* 552unsigned CUpdateItem::GetExtensionPos() const 553{ 554 int slashPos = Name.ReverseFind_PathSepar(); 555 int dotPos = Name.ReverseFind_Dot(); 556 if (dotPos <= slashPos) 557 return Name.Len(); 558 return dotPos + 1; 559} 560 561UString CUpdateItem::GetExtension() const 562{ 563 return Name.Ptr(GetExtensionPos()); 564} 565*/ 566 567#define RINOZ(x) { const int _t_ = (x); if (_t_ != 0) return _t_; } 568 569#define RINOZ_COMP(a, b) RINOZ(MyCompare(a, b)) 570 571/* 572static int CompareBuffers(const CByteBuffer &a1, const CByteBuffer &a2) 573{ 574 size_t c1 = a1.GetCapacity(); 575 size_t c2 = a2.GetCapacity(); 576 RINOZ_COMP(c1, c2); 577 for (size_t i = 0; i < c1; i++) 578 RINOZ_COMP(a1[i], a2[i]); 579 return 0; 580} 581 582static int CompareCoders(const CCoderInfo &c1, const CCoderInfo &c2) 583{ 584 RINOZ_COMP(c1.NumInStreams, c2.NumInStreams); 585 RINOZ_COMP(c1.NumOutStreams, c2.NumOutStreams); 586 RINOZ_COMP(c1.MethodID, c2.MethodID); 587 return CompareBuffers(c1.Props, c2.Props); 588} 589 590static int CompareBonds(const CBond &b1, const CBond &b2) 591{ 592 RINOZ_COMP(b1.InIndex, b2.InIndex); 593 return MyCompare(b1.OutIndex, b2.OutIndex); 594} 595 596static int CompareFolders(const CFolder &f1, const CFolder &f2) 597{ 598 int s1 = f1.Coders.Size(); 599 int s2 = f2.Coders.Size(); 600 RINOZ_COMP(s1, s2); 601 int i; 602 for (i = 0; i < s1; i++) 603 RINOZ(CompareCoders(f1.Coders[i], f2.Coders[i])); 604 s1 = f1.Bonds.Size(); 605 s2 = f2.Bonds.Size(); 606 RINOZ_COMP(s1, s2); 607 for (i = 0; i < s1; i++) 608 RINOZ(CompareBonds(f1.Bonds[i], f2.Bonds[i])); 609 return 0; 610} 611*/ 612 613/* 614static int CompareFiles(const CFileItem &f1, const CFileItem &f2) 615{ 616 return CompareFileNames(f1.Name, f2.Name); 617} 618*/ 619 620struct CFolderRepack 621{ 622 unsigned FolderIndex; 623 CNum NumCopyFiles; 624}; 625 626/* 627static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *) 628{ 629 int i1 = p1->FolderIndex; 630 int i2 = p2->FolderIndex; 631 // In that version we don't want to parse folders here, so we don't compare folders 632 // probably it must be improved in future 633 // const CDbEx &db = *(const CDbEx *)param; 634 // RINOZ(CompareFolders( 635 // db.Folders[i1], 636 // db.Folders[i2])); 637 638 return MyCompare(i1, i2); 639 640 // RINOZ_COMP( 641 // db.NumUnpackStreamsVector[i1], 642 // db.NumUnpackStreamsVector[i2]); 643 // if (db.NumUnpackStreamsVector[i1] == 0) 644 // return 0; 645 // return CompareFiles( 646 // db.Files[db.FolderStartFileIndex[i1]], 647 // db.Files[db.FolderStartFileIndex[i2]]); 648} 649*/ 650 651/* 652 we sort empty files and dirs in such order: 653 - Dir.NonAnti (name sorted) 654 - File.NonAnti (name sorted) 655 - File.Anti (name sorted) 656 - Dir.Anti (reverse name sorted) 657*/ 658 659static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param) 660{ 661 const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param; 662 const CUpdateItem &u1 = updateItems[*p1]; 663 const CUpdateItem &u2 = updateItems[*p2]; 664 // NonAnti < Anti 665 if (u1.IsAnti != u2.IsAnti) 666 return (u1.IsAnti ? 1 : -1); 667 if (u1.IsDir != u2.IsDir) 668 { 669 // Dir.NonAnti < File < Dir.Anti 670 if (u1.IsDir) 671 return (u1.IsAnti ? 1 : -1); 672 return (u2.IsAnti ? -1 : 1); 673 } 674 int n = CompareFileNames(u1.Name, u2.Name); 675 return (u1.IsDir && u1.IsAnti) ? -n : n; 676} 677 678static const char *g_Exts = 679 " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit zoo" 680 " zip jar ear war msi" 681 " 3gp avi mov mpeg mpg mpe wmv" 682 " aac ape fla flac la mp3 m4a mp4 ofr ogg pac ra rm rka shn swa tta wv wma wav" 683 " swf" 684 " chm hxi hxs" 685 " gif jpeg jpg jp2 png tiff bmp ico psd psp" 686 " awg ps eps cgm dxf svg vrml wmf emf ai md" 687 " cad dwg pps key sxi" 688 " max 3ds" 689 " iso bin nrg mdf img pdi tar cpio xpi" 690 " vfd vhd vud vmc vsv" 691 " vmdk dsk nvram vmem vmsd vmsn vmss vmtm" 692 " inl inc idl acf asa" 693 " h hpp hxx c cpp cxx m mm go swift" 694 " rc java cs rs pas bas vb cls ctl frm dlg def" 695 " f77 f f90 f95" 696 " asm s" 697 " sql manifest dep" 698 " mak clw csproj vcproj sln dsp dsw" 699 " class" 700 " bat cmd bash sh" 701 " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml" 702 " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts vbs" 703 " text txt tex ans asc srt reg ini doc docx mcw dot rtf hlp xls xlr xlt xlw ppt pdf" 704 " sxc sxd sxi sxg sxw stc sti stw stm odt ott odg otg odp otp ods ots odf" 705 " abw afp cwk lwp wpd wps wpt wrf wri" 706 " abf afm bdf fon mgf otf pcf pfa snf ttf" 707 " dbf mdb nsf ntf wdb db fdb gdb" 708 " exe dll ocx vbx sfx sys tlb awx com obj lib out o so" 709 " pdb pch idb ncb opt"; 710 711static unsigned GetExtIndex(const char *ext) 712{ 713 unsigned extIndex = 1; 714 const char *p = g_Exts; 715 for (;;) 716 { 717 char c = *p++; 718 if (c == 0) 719 return extIndex; 720 if (c == ' ') 721 continue; 722 unsigned pos = 0; 723 for (;;) 724 { 725 char c2 = ext[pos++]; 726 if (c2 == 0 && (c == 0 || c == ' ')) 727 return extIndex; 728 if (c != c2) 729 break; 730 c = *p++; 731 } 732 extIndex++; 733 for (;;) 734 { 735 if (c == 0) 736 return extIndex; 737 if (c == ' ') 738 break; 739 c = *p++; 740 } 741 } 742} 743 744struct CRefItem 745{ 746 const CUpdateItem *UpdateItem; 747 UInt32 Index; 748 unsigned ExtensionPos; 749 unsigned NamePos; 750 unsigned ExtensionIndex; 751 752 CRefItem() {} 753 CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType): 754 UpdateItem(&ui), 755 Index(index), 756 ExtensionPos(0), 757 NamePos(0), 758 ExtensionIndex(0) 759 { 760 if (sortByType) 761 { 762 int slashPos = ui.Name.ReverseFind_PathSepar(); 763 NamePos = (unsigned)(slashPos + 1); 764 int dotPos = ui.Name.ReverseFind_Dot(); 765 if (dotPos <= slashPos) 766 ExtensionPos = ui.Name.Len(); 767 else 768 { 769 ExtensionPos = (unsigned)(dotPos + 1); 770 if (ExtensionPos != ui.Name.Len()) 771 { 772 AString s; 773 for (unsigned pos = ExtensionPos;; pos++) 774 { 775 wchar_t c = ui.Name[pos]; 776 if (c >= 0x80) 777 break; 778 if (c == 0) 779 { 780 ExtensionIndex = GetExtIndex(s); 781 break; 782 } 783 s += (char)MyCharLower_Ascii((char)c); 784 } 785 } 786 } 787 } 788 } 789}; 790 791struct CSortParam 792{ 793 // const CObjectVector<CTreeFolder> *TreeFolders; 794 bool SortByType; 795}; 796 797/* 798 we sort files in such order: 799 - Dir.NonAnti (name sorted) 800 - alt streams 801 - Dirs 802 - Dir.Anti (reverse name sorted) 803*/ 804 805 806static int CompareUpdateItems(const CRefItem *p1, const CRefItem *p2, void *param) 807{ 808 const CRefItem &a1 = *p1; 809 const CRefItem &a2 = *p2; 810 const CUpdateItem &u1 = *a1.UpdateItem; 811 const CUpdateItem &u2 = *a2.UpdateItem; 812 813 /* 814 if (u1.IsAltStream != u2.IsAltStream) 815 return u1.IsAltStream ? 1 : -1; 816 */ 817 818 // Actually there are no dirs that time. They were stored in other steps 819 // So that code is unused? 820 if (u1.IsDir != u2.IsDir) 821 return u1.IsDir ? 1 : -1; 822 if (u1.IsDir) 823 { 824 if (u1.IsAnti != u2.IsAnti) 825 return (u1.IsAnti ? 1 : -1); 826 int n = CompareFileNames(u1.Name, u2.Name); 827 return -n; 828 } 829 830 // bool sortByType = *(bool *)param; 831 const CSortParam *sortParam = (const CSortParam *)param; 832 const bool sortByType = sortParam->SortByType; 833 if (sortByType) 834 { 835 RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex) 836 RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos))) 837 RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(a2.NamePos))) 838 if (!u1.MTimeDefined && u2.MTimeDefined) return 1; 839 if (u1.MTimeDefined && !u2.MTimeDefined) return -1; 840 if (u1.MTimeDefined && u2.MTimeDefined) RINOZ_COMP(u1.MTime, u2.MTime) 841 RINOZ_COMP(u1.Size, u2.Size) 842 } 843 /* 844 int par1 = a1.UpdateItem->ParentFolderIndex; 845 int par2 = a2.UpdateItem->ParentFolderIndex; 846 const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1]; 847 const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2]; 848 849 int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd; 850 int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd; 851 if (b1 < b2) 852 { 853 if (e1 <= b2) 854 return -1; 855 // p2 in p1 856 int par = par2; 857 for (;;) 858 { 859 const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; 860 par = tf.Parent; 861 if (par == par1) 862 { 863 RINOZ(CompareFileNames(u1.Name, tf.Name)); 864 break; 865 } 866 } 867 } 868 else if (b2 < b1) 869 { 870 if (e2 <= b1) 871 return 1; 872 // p1 in p2 873 int par = par1; 874 for (;;) 875 { 876 const CTreeFolder &tf = (*sortParam->TreeFolders)[par]; 877 par = tf.Parent; 878 if (par == par2) 879 { 880 RINOZ(CompareFileNames(tf.Name, u2.Name)); 881 break; 882 } 883 } 884 } 885 */ 886 // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex); 887 RINOK(CompareFileNames(u1.Name, u2.Name)) 888 RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient) 889 RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive) 890 return 0; 891} 892 893struct CSolidGroup 894{ 895 CRecordVector<UInt32> Indices; 896 897 CRecordVector<CFolderRepack> folderRefs; 898}; 899 900static const char * const g_Exe_Exts[] = 901{ 902 "dll" 903 , "exe" 904 , "ocx" 905 , "sfx" 906 , "sys" 907}; 908 909static const char * const g_ExeUnix_Exts[] = 910{ 911 "so" 912 , "dylib" 913}; 914 915static bool IsExt_Exe(const wchar_t *ext) 916{ 917 for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Exe_Exts); i++) 918 if (StringsAreEqualNoCase_Ascii(ext, g_Exe_Exts[i])) 919 return true; 920 return false; 921} 922 923/* 924static bool IsExt_ExeUnix(const wchar_t *ext) 925{ 926 for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExeUnix_Exts); i++) 927 if (StringsAreEqualNoCase_Ascii(ext, g_ExeUnix_Exts[i])) 928 return true; 929 return false; 930} 931*/ 932 933// we try to find "so" extension in such name: libstdc++.so.6.0.29 934static bool IsExt_ExeUnix_NumericAllowed(const UString &path) 935{ 936 unsigned pos = path.Len(); 937 unsigned dotPos = pos; 938 for (;;) 939 { 940 if (pos == 0) 941 return false; 942 const wchar_t c = path[--pos]; 943 if (IS_PATH_SEPAR(c)) 944 return false; 945 if (c == '.') 946 { 947 const unsigned num = (dotPos - pos) - 1; 948 if (num < 1) 949 return false; 950 const wchar_t *cur = path.Ptr(pos + 1); 951 for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExeUnix_Exts); i++) 952 { 953 const char *ext = g_ExeUnix_Exts[i]; 954 if (num == MyStringLen(ext)) 955 if (IsString1PrefixedByString2_NoCase_Ascii(cur, ext)) 956 return true; 957 } 958 const wchar_t *end; 959 ConvertStringToUInt32(cur, &end); 960 if ((size_t)(end - cur) != num) 961 return false; 962 dotPos = pos; 963 } 964 } 965} 966 967 968struct CAnalysis 969{ 970 CMyComPtr<IArchiveUpdateCallbackFile> Callback; 971 CByteBuffer Buffer; 972 973 bool ParseWav; 974 bool ParseExe; 975 bool ParseExeUnix; 976 bool ParseNoExt; 977 bool ParseAll; 978 979 /* 980 bool Need_ATime; 981 bool ATime_Defined; 982 FILETIME ATime; 983 */ 984 985 CAnalysis(): 986 ParseWav(false), 987 ParseExe(false), 988 ParseExeUnix(false), 989 ParseNoExt(false), 990 ParseAll(false) 991 /* 992 , Need_ATime(false) 993 , ATime_Defined(false) 994 */ 995 {} 996 997 HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode); 998}; 999 1000static const size_t kAnalysisBufSize = 1 << 14; 1001 1002HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode) 1003{ 1004 filterMode.Id = 0; 1005 filterMode.Delta = 0; 1006 filterMode.Offset = 0; 1007 1008 CFilterMode filterModeTemp = filterMode; 1009 1010 const int slashPos = ui.Name.ReverseFind_PathSepar(); 1011 const int dotPos = ui.Name.ReverseFind_Dot(); 1012 1013 // if (dotPos > slashPos) 1014 { 1015 bool needReadFile = ParseAll; 1016 /* if (Callback) is not supported by client, 1017 we still try to use file name extension to detect executable file */ 1018 bool probablyIsSameIsa = false; 1019 1020 if (!needReadFile || !Callback) 1021 { 1022 const wchar_t *ext = NULL; 1023 if (dotPos > slashPos) 1024 ext = ui.Name.Ptr((unsigned)(dotPos + 1)); 1025 // 7-zip stores posix attributes in high 16 bits and sets (0x8000) flag 1026 if (ui.Attrib & 0x8000) 1027 { 1028 const unsigned st_mode = ui.Attrib >> 16; 1029 /* note: executable ".so" can be without execute permission, 1030 and symbolic link to such ".so" file is possible */ 1031 // st_mode = 00111; // for debug 1032 /* in Linux we expect such permissions: 1033 0755 : for most executables 1034 0644 : for some ".so" files 1035 0777 : in WSL for all files. 1036 We can try to exclude some such 0777 cases from analysis, 1037 if there is non-executable extension. 1038 */ 1039 1040 if ((st_mode & ( 1041 MY_LIN_S_IXUSR | 1042 MY_LIN_S_IXGRP | 1043 MY_LIN_S_IXOTH)) != 0 1044 && MY_LIN_S_ISREG(st_mode) 1045 && (ui.Size >= (1u << 11))) 1046 { 1047 #ifndef _WIN32 1048 probablyIsSameIsa = true; 1049 #endif 1050 needReadFile = true; 1051 } 1052 } 1053 1054 if (!needReadFile) 1055 { 1056 if (!ext) 1057 needReadFile = ParseNoExt; 1058 else 1059 { 1060 bool isUnixExt = false; 1061 if (ParseExeUnix) 1062 isUnixExt = IsExt_ExeUnix_NumericAllowed(ui.Name); 1063 if (isUnixExt) 1064 { 1065 needReadFile = true; 1066 #ifndef _WIN32 1067 probablyIsSameIsa = true; 1068 #endif 1069 } 1070 else if (IsExt_Exe(ext)) 1071 { 1072 needReadFile = ParseExe; 1073 #ifdef _WIN32 1074 probablyIsSameIsa = true; 1075 #endif 1076 } 1077 else if (StringsAreEqualNoCase_Ascii(ext, "wav")) 1078 { 1079 if (!needReadFile) 1080 needReadFile = ParseWav; 1081 } 1082 } 1083 } 1084 } 1085 1086 if (needReadFile) 1087 { 1088 BoolInt parseRes = false; 1089 if (Callback) 1090 { 1091 if (Buffer.Size() != kAnalysisBufSize) 1092 Buffer.Alloc(kAnalysisBufSize); 1093 CMyComPtr<ISequentialInStream> stream; 1094 HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze); 1095 if (result == S_OK && stream) 1096 { 1097 /* 1098 if (Need_ATime) 1099 { 1100 // access time could be changed in analysis pass 1101 CMyComPtr<IStreamGetProps> getProps; 1102 stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps); 1103 if (getProps) 1104 if (getProps->GetProps(NULL, NULL, &ATime, NULL, NULL) == S_OK) 1105 ATime_Defined = true; 1106 } 1107 */ 1108 size_t size = kAnalysisBufSize; 1109 result = ReadStream(stream, Buffer, &size); 1110 stream.Release(); 1111 // RINOK(Callback->SetOperationResult2(index, NUpdate::NOperationResult::kOK)); 1112 if (result == S_OK) 1113 { 1114 parseRes = ParseFile(Buffer, size, &filterModeTemp); 1115 } 1116 } 1117 } // Callback 1118 else if (probablyIsSameIsa) 1119 { 1120 #ifdef MY_CPU_X86_OR_AMD64 1121 filterModeTemp.Id = k_X86; 1122 #endif 1123 #ifdef MY_CPU_ARM64 1124 filterModeTemp.Id = k_ARM64; 1125 #endif 1126 parseRes = true; 1127 } 1128 1129 if (parseRes 1130 && filterModeTemp.Id != k_Delta 1131 && filterModeTemp.Delta == 0) 1132 { 1133 /* ParseFile() sets (filterModeTemp.Delta == 0) for all 1134 methods except of k_Delta. */ 1135 // it's not k_Delta 1136 // So we call SetDelta() to set Delta 1137 filterModeTemp.SetDelta(); 1138 if (filterModeTemp.Delta > 1) 1139 { 1140 /* If file Size is not aligned, then branch filter 1141 will not work for next file in solid block. 1142 Maybe we should allow filter for non-aligned-size file in non-solid archives ? 1143 */ 1144 if (ui.Size % filterModeTemp.Delta != 0) 1145 parseRes = false; 1146 // windows exe files are not aligned for 4 KiB. 1147 /* 1148 else if (filterModeTemp.Id == k_ARM64 && filterModeTemp.Offset != 0) 1149 { 1150 if (ui.Size % (1 << 12) != 0) 1151 { 1152 // If Size is not aligned for 4 KiB, then Offset will not work for next file in solid block. 1153 // so we place such file in group with (Offset==0). 1154 filterModeTemp.Offset = 0; 1155 } 1156 } 1157 */ 1158 } 1159 } 1160 if (!parseRes) 1161 filterModeTemp.ClearFilterMode(); 1162 } 1163 } 1164 1165 filterMode = filterModeTemp; 1166 return S_OK; 1167} 1168 1169static inline void GetMethodFull(UInt64 methodID, UInt32 numStreams, CMethodFull &m) 1170{ 1171 m.Id = methodID; 1172 m.NumStreams = numStreams; 1173} 1174 1175static HRESULT AddBondForFilter(CCompressionMethodMode &mode) 1176{ 1177 for (unsigned c = 1; c < mode.Methods.Size(); c++) 1178 { 1179 if (!mode.IsThereBond_to_Coder(c)) 1180 { 1181 CBond2 bond; 1182 bond.OutCoder = 0; 1183 bond.OutStream = 0; 1184 bond.InCoder = c; 1185 mode.Bonds.Add(bond); 1186 return S_OK; 1187 } 1188 } 1189 return E_INVALIDARG; 1190} 1191 1192static HRESULT AddFilterBond(CCompressionMethodMode &mode) 1193{ 1194 if (!mode.Bonds.IsEmpty()) 1195 return AddBondForFilter(mode); 1196 return S_OK; 1197} 1198 1199static HRESULT AddBcj2Methods(CCompressionMethodMode &mode) 1200{ 1201 // mode.Methods[0] must be k_BCJ2 method ! 1202 1203 CMethodFull m; 1204 GetMethodFull(k_LZMA, 1, m); 1205 1206 m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20); 1207 m.AddProp32(NCoderPropID::kNumFastBytes, 128); 1208 m.AddProp32(NCoderPropID::kNumThreads, 1); 1209 m.AddProp32(NCoderPropID::kLitPosBits, 2); 1210 m.AddProp32(NCoderPropID::kLitContextBits, 0); 1211 // m.AddProp_Ascii(NCoderPropID::kMatchFinder, "BT2"); 1212 1213 unsigned methodIndex = mode.Methods.Size(); 1214 1215 if (mode.Bonds.IsEmpty()) 1216 { 1217 for (unsigned i = 1; i + 1 < mode.Methods.Size(); i++) 1218 { 1219 CBond2 bond; 1220 bond.OutCoder = i; 1221 bond.OutStream = 0; 1222 bond.InCoder = i + 1; 1223 mode.Bonds.Add(bond); 1224 } 1225 } 1226 1227 mode.Methods.Add(m); 1228 mode.Methods.Add(m); 1229 1230 RINOK(AddBondForFilter(mode)) 1231 CBond2 bond; 1232 bond.OutCoder = 0; 1233 bond.InCoder = methodIndex; bond.OutStream = 1; mode.Bonds.Add(bond); 1234 bond.InCoder = methodIndex + 1; bond.OutStream = 2; mode.Bonds.Add(bond); 1235 return S_OK; 1236} 1237 1238static HRESULT MakeExeMethod(CCompressionMethodMode &mode, 1239 const CFilterMode &filterMode, /* bool addFilter, */ bool bcj2Filter) 1240{ 1241 if (mode.Filter_was_Inserted) 1242 { 1243 const CMethodFull &m = mode.Methods[0]; 1244 const CMethodId id = m.Id; 1245 if (id == k_BCJ2) 1246 return AddBcj2Methods(mode); 1247 if (!m.IsSimpleCoder()) 1248 return E_NOTIMPL; 1249 // if (Bonds.IsEmpty()) we can create bonds later 1250 return AddFilterBond(mode); 1251 } 1252 1253 if (filterMode.Id == 0) 1254 return S_OK; 1255 1256 CMethodFull &m = mode.Methods.InsertNew(0); 1257 1258 { 1259 FOR_VECTOR (k, mode.Bonds) 1260 { 1261 CBond2 &bond = mode.Bonds[k]; 1262 bond.InCoder++; 1263 bond.OutCoder++; 1264 } 1265 } 1266 1267 HRESULT res; 1268 1269 if (bcj2Filter && Is86Filter(filterMode.Id)) 1270 { 1271 GetMethodFull(k_BCJ2, 4, m); 1272 res = AddBcj2Methods(mode); 1273 } 1274 else 1275 { 1276 GetMethodFull(filterMode.Id, 1, m); 1277 if (filterMode.Id == k_Delta) 1278 m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta); 1279 else if (filterMode.Id == k_ARM64) 1280 { 1281 // if (filterMode.Offset != 0) 1282 m.AddProp32( 1283 NCoderPropID::kDefaultProp, 1284 // NCoderPropID::kBranchOffset, 1285 filterMode.Offset); 1286 } 1287 res = AddFilterBond(mode); 1288 1289 int alignBits = -1; 1290 { 1291 const UInt32 delta = filterMode.Delta; 1292 if (delta == 0 || delta > 16) 1293 { 1294 // if (delta == 0) alignBits = GetAlignForFilterMethod(filterMode.Id); 1295 } 1296 else if ((delta & ((1 << 4) - 1)) == 0) alignBits = 4; 1297 else if ((delta & ((1 << 3) - 1)) == 0) alignBits = 3; 1298 else if ((delta & ((1 << 2) - 1)) == 0) alignBits = 2; 1299 else if ((delta & ((1 << 1) - 1)) == 0) alignBits = 1; 1300 // else alignBits = 0; 1301 /* alignBits=0 is default mode for lzma/lzma2. 1302 So we don't set alignBits=0 here. */ 1303 } 1304 if (res == S_OK && alignBits > 0) 1305 { 1306 unsigned nextCoder = 1; 1307 if (!mode.Bonds.IsEmpty()) 1308 { 1309 nextCoder = mode.Bonds.Back().InCoder; 1310 } 1311 if (nextCoder < mode.Methods.Size()) 1312 { 1313 CMethodFull &nextMethod = mode.Methods[nextCoder]; 1314 if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2) 1315 { 1316 if (!nextMethod.Are_Lzma_Model_Props_Defined()) 1317 { 1318 if (alignBits != 0) 1319 { 1320 if (alignBits > 2 || filterMode.Id == k_Delta) 1321 nextMethod.AddProp32(NCoderPropID::kPosStateBits, (unsigned)alignBits); 1322 unsigned lc = 0; 1323 if (alignBits < 3) 1324 lc = (unsigned)(3 - alignBits); 1325 nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc); 1326 nextMethod.AddProp32(NCoderPropID::kLitPosBits, (unsigned)alignBits); 1327 } 1328 } 1329 } 1330 } 1331 } 1332 } 1333 1334 return res; 1335} 1336 1337 1338static void UpdateItem_To_FileItem2(const CUpdateItem &ui, CFileItem2 &file2) 1339{ 1340 file2.Attrib = ui.Attrib; file2.AttribDefined = ui.AttribDefined; 1341 file2.CTime = ui.CTime; file2.CTimeDefined = ui.CTimeDefined; 1342 file2.ATime = ui.ATime; file2.ATimeDefined = ui.ATimeDefined; 1343 file2.MTime = ui.MTime; file2.MTimeDefined = ui.MTimeDefined; 1344 file2.IsAnti = ui.IsAnti; 1345 // file2.IsAux = false; 1346 file2.StartPosDefined = false; 1347 // file2.StartPos = 0; 1348} 1349 1350 1351static void UpdateItem_To_FileItem(const CUpdateItem &ui, 1352 CFileItem &file, CFileItem2 &file2) 1353{ 1354 UpdateItem_To_FileItem2(ui, file2); 1355 1356 file.Size = ui.Size; 1357 file.IsDir = ui.IsDir; 1358 file.HasStream = ui.HasStream(); 1359 // file.IsAltStream = ui.IsAltStream; 1360} 1361 1362 1363 1364Z7_CLASS_IMP_COM_2( 1365 CRepackInStreamWithSizes 1366 , ISequentialInStream 1367 , ICompressGetSubStreamSize 1368) 1369 CMyComPtr<ISequentialInStream> _stream; 1370 UInt64 _size; 1371 const CBoolVector *_extractStatuses; 1372 UInt32 _startIndex; 1373public: 1374 const CDbEx *_db; 1375 1376 void Init(ISequentialInStream *stream, UInt32 startIndex, const CBoolVector *extractStatuses) 1377 { 1378 _startIndex = startIndex; 1379 _extractStatuses = extractStatuses; 1380 _size = 0; 1381 _stream = stream; 1382 } 1383 UInt64 GetSize() const { return _size; } 1384}; 1385 1386Z7_COM7F_IMF(CRepackInStreamWithSizes::Read(void *data, UInt32 size, UInt32 *processedSize)) 1387{ 1388 UInt32 realProcessedSize; 1389 const HRESULT result = _stream->Read(data, size, &realProcessedSize); 1390 _size += realProcessedSize; 1391 if (processedSize) 1392 *processedSize = realProcessedSize; 1393 return result; 1394} 1395 1396Z7_COM7F_IMF(CRepackInStreamWithSizes::GetSubStreamSize(UInt64 subStream, UInt64 *value)) 1397{ 1398 *value = 0; 1399 if (subStream >= _extractStatuses->Size()) 1400 return S_FALSE; // E_FAIL; 1401 const unsigned index = (unsigned)subStream; 1402 if ((*_extractStatuses)[index]) 1403 { 1404 const CFileItem &fi = _db->Files[_startIndex + index]; 1405 if (fi.HasStream) 1406 *value = fi.Size; 1407 } 1408 return S_OK; 1409} 1410 1411 1412class CRepackStreamBase 1413{ 1414protected: 1415 bool _needWrite; 1416 bool _fileIsOpen; 1417 bool _calcCrc; 1418 UInt32 _crc; 1419 UInt64 _rem; 1420 1421 const CBoolVector *_extractStatuses; 1422 UInt32 _startIndex; 1423 unsigned _currentIndex; 1424 1425 HRESULT OpenFile(); 1426 HRESULT CloseFile(); 1427 HRESULT ProcessEmptyFiles(); 1428 1429public: 1430 const CDbEx *_db; 1431 CMyComPtr<IArchiveUpdateCallbackFile> _opCallback; 1432 CMyComPtr<IArchiveExtractCallbackMessage2> _extractCallback; 1433 1434 HRESULT Init(UInt32 startIndex, const CBoolVector *extractStatuses); 1435 HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; } 1436}; 1437 1438HRESULT CRepackStreamBase::Init(UInt32 startIndex, const CBoolVector *extractStatuses) 1439{ 1440 _startIndex = startIndex; 1441 _extractStatuses = extractStatuses; 1442 1443 _currentIndex = 0; 1444 _fileIsOpen = false; 1445 1446 return ProcessEmptyFiles(); 1447} 1448 1449HRESULT CRepackStreamBase::OpenFile() 1450{ 1451 UInt32 arcIndex = _startIndex + _currentIndex; 1452 const CFileItem &fi = _db->Files[arcIndex]; 1453 1454 _needWrite = (*_extractStatuses)[_currentIndex]; 1455 if (_opCallback) 1456 { 1457 RINOK(_opCallback->ReportOperation( 1458 NEventIndexType::kInArcIndex, arcIndex, 1459 _needWrite ? 1460 NUpdateNotifyOp::kRepack : 1461 NUpdateNotifyOp::kSkip)) 1462 } 1463 1464 _crc = CRC_INIT_VAL; 1465 _calcCrc = (fi.CrcDefined && !fi.IsDir); 1466 1467 _fileIsOpen = true; 1468 _rem = fi.Size; 1469 return S_OK; 1470} 1471 1472const HRESULT k_My_HRESULT_CRC_ERROR = 0x20000002; 1473 1474HRESULT CRepackStreamBase::CloseFile() 1475{ 1476 UInt32 arcIndex = _startIndex + _currentIndex; 1477 const CFileItem &fi = _db->Files[arcIndex]; 1478 _fileIsOpen = false; 1479 _currentIndex++; 1480 if (!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) 1481 return S_OK; 1482 1483 if (_extractCallback) 1484 { 1485 RINOK(_extractCallback->ReportExtractResult( 1486 NEventIndexType::kInArcIndex, arcIndex, 1487 NExtract::NOperationResult::kCRCError)) 1488 } 1489 // return S_FALSE; 1490 return k_My_HRESULT_CRC_ERROR; 1491} 1492 1493HRESULT CRepackStreamBase::ProcessEmptyFiles() 1494{ 1495 while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0) 1496 { 1497 RINOK(OpenFile()) 1498 RINOK(CloseFile()) 1499 } 1500 return S_OK; 1501} 1502 1503 1504 1505#ifndef Z7_ST 1506 1507class CFolderOutStream2 Z7_final: 1508 public CRepackStreamBase, 1509 public ISequentialOutStream, 1510 public CMyUnknownImp 1511{ 1512 Z7_COM_UNKNOWN_IMP_0 1513 Z7_IFACE_COM7_IMP(ISequentialOutStream) 1514public: 1515 CMyComPtr<ISequentialOutStream> _stream; 1516}; 1517 1518Z7_COM7F_IMF(CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)) 1519{ 1520 if (processedSize) 1521 *processedSize = 0; 1522 1523 while (size != 0) 1524 { 1525 if (_fileIsOpen) 1526 { 1527 UInt32 cur = (size < _rem ? size : (UInt32)_rem); 1528 HRESULT result = S_OK; 1529 if (_needWrite) 1530 result = _stream->Write(data, cur, &cur); 1531 if (_calcCrc) 1532 _crc = CrcUpdate(_crc, data, cur); 1533 if (processedSize) 1534 *processedSize += cur; 1535 data = (const Byte *)data + cur; 1536 size -= cur; 1537 _rem -= cur; 1538 if (_rem == 0) 1539 { 1540 RINOK(CloseFile()) 1541 RINOK(ProcessEmptyFiles()) 1542 } 1543 RINOK(result) 1544 if (cur == 0) 1545 break; 1546 continue; 1547 } 1548 1549 RINOK(ProcessEmptyFiles()) 1550 if (_currentIndex == _extractStatuses->Size()) 1551 { 1552 // we don't support write cut here 1553 return E_FAIL; 1554 } 1555 RINOK(OpenFile()) 1556 } 1557 1558 return S_OK; 1559} 1560 1561#endif 1562 1563 1564 1565static const UInt32 kTempBufSize = 1 << 16; 1566 1567class CFolderInStream2 Z7_final: 1568 public CRepackStreamBase, 1569 public ISequentialInStream, 1570 public CMyUnknownImp 1571{ 1572 Z7_COM_UNKNOWN_IMP_0 1573 Z7_IFACE_COM7_IMP(ISequentialInStream) 1574 1575 Byte *_buf; 1576public: 1577 CMyComPtr<ISequentialInStream> _inStream; 1578 HRESULT Result; 1579 1580 CFolderInStream2(): 1581 Result(S_OK) 1582 { 1583 _buf = new Byte[kTempBufSize]; 1584 } 1585 1586 ~CFolderInStream2() 1587 { 1588 delete []_buf; 1589 } 1590 1591 void Init() { Result = S_OK; } 1592}; 1593 1594Z7_COM7F_IMF(CFolderInStream2::Read(void *data, UInt32 size, UInt32 *processedSize)) 1595{ 1596 if (processedSize) 1597 *processedSize = 0; 1598 1599 while (size != 0) 1600 { 1601 if (_fileIsOpen) 1602 { 1603 UInt32 cur = (size < _rem ? size : (UInt32)_rem); 1604 1605 void *buf; 1606 if (_needWrite) 1607 buf = data; 1608 else 1609 { 1610 buf = _buf; 1611 if (cur > kTempBufSize) 1612 cur = kTempBufSize; 1613 } 1614 1615 const HRESULT result = _inStream->Read(buf, cur, &cur); 1616 _crc = CrcUpdate(_crc, buf, cur); 1617 _rem -= cur; 1618 1619 if (_needWrite) 1620 { 1621 data = (Byte *)data + cur; 1622 size -= cur; 1623 if (processedSize) 1624 *processedSize += cur; 1625 } 1626 1627 if (result != S_OK) 1628 Result = result; 1629 1630 if (_rem == 0) 1631 { 1632 RINOK(CloseFile()) 1633 RINOK(ProcessEmptyFiles()) 1634 } 1635 1636 RINOK(result) 1637 1638 if (cur == 0) 1639 return E_FAIL; 1640 1641 continue; 1642 } 1643 1644 RINOK(ProcessEmptyFiles()) 1645 if (_currentIndex == _extractStatuses->Size()) 1646 { 1647 return S_OK; 1648 } 1649 RINOK(OpenFile()) 1650 } 1651 1652 return S_OK; 1653} 1654 1655 1656class CThreadDecoder Z7_final 1657 #ifndef Z7_ST 1658 : public CVirtThread 1659 #endif 1660{ 1661public: 1662 CDecoder Decoder; 1663 1664 CThreadDecoder(bool multiThreadMixer): 1665 Decoder(multiThreadMixer) 1666 { 1667 #ifndef Z7_ST 1668 if (multiThreadMixer) 1669 { 1670 MtMode = false; 1671 NumThreads = 1; 1672 FosSpec = new CFolderOutStream2; 1673 Fos = FosSpec; 1674 Result = E_FAIL; 1675 } 1676 #endif 1677 // UnpackSize = 0; 1678 // send_UnpackSize = false; 1679 } 1680 1681 #ifndef Z7_ST 1682 1683 bool dataAfterEnd_Error; 1684 HRESULT Result; 1685 CMyComPtr<IInStream> InStream; 1686 1687 CFolderOutStream2 *FosSpec; 1688 CMyComPtr<ISequentialOutStream> Fos; 1689 1690 UInt64 StartPos; 1691 const CFolders *Folders; 1692 unsigned FolderIndex; 1693 1694 // bool send_UnpackSize; 1695 // UInt64 UnpackSize; 1696 1697 #ifndef Z7_NO_CRYPTO 1698 CMyComPtr<ICryptoGetTextPassword> getTextPassword; 1699 #endif 1700 1701 DECL_EXTERNAL_CODECS_LOC_VARS_DECL 1702 1703 #ifndef Z7_ST 1704 bool MtMode; 1705 UInt32 NumThreads; 1706 #endif 1707 1708 1709 ~CThreadDecoder() Z7_DESTRUCTOR_override 1710 { 1711 /* WaitThreadFinish() will be called in ~CVirtThread(). 1712 But we need WaitThreadFinish() call before 1713 destructors of this class members. 1714 */ 1715 CVirtThread::WaitThreadFinish(); 1716 } 1717private: 1718 virtual void Execute() Z7_override; 1719 1720 #endif 1721}; 1722 1723#ifndef Z7_ST 1724 1725void CThreadDecoder::Execute() 1726{ 1727 try 1728 { 1729 #ifndef Z7_NO_CRYPTO 1730 bool isEncrypted = false; 1731 bool passwordIsDefined = false; 1732 UString password; 1733 #endif 1734 1735 dataAfterEnd_Error = false; 1736 1737 Result = Decoder.Decode( 1738 EXTERNAL_CODECS_LOC_VARS 1739 InStream, 1740 StartPos, 1741 *Folders, FolderIndex, 1742 1743 // send_UnpackSize ? &UnpackSize : NULL, 1744 NULL, // unpackSize : FULL unpack 1745 1746 Fos, 1747 NULL, // compressProgress 1748 1749 NULL // *inStreamMainRes 1750 , dataAfterEnd_Error 1751 1752 Z7_7Z_DECODER_CRYPRO_VARS 1753 #ifndef Z7_ST 1754 , MtMode, NumThreads, 1755 0 // MemUsage 1756 #endif 1757 1758 ); 1759 } 1760 catch(...) 1761 { 1762 Result = E_FAIL; 1763 } 1764 1765 /* 1766 if (Result == S_OK) 1767 Result = FosSpec->CheckFinishedState(); 1768 */ 1769 FosSpec->_stream.Release(); 1770} 1771 1772#endif 1773 1774#ifndef Z7_NO_CRYPTO 1775 1776Z7_CLASS_IMP_NOQIB_1( 1777 CCryptoGetTextPassword 1778 , ICryptoGetTextPassword 1779) 1780public: 1781 UString Password; 1782}; 1783 1784Z7_COM7F_IMF(CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password)) 1785{ 1786 return StringToBstr(Password, password); 1787} 1788 1789#endif 1790 1791 1792static void GetFile(const CDatabase &inDb, unsigned index, CFileItem &file, CFileItem2 &file2) 1793{ 1794 file = inDb.Files[index]; 1795 file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime); 1796 file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime); 1797 file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime); 1798 file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos); 1799 file2.AttribDefined = inDb.Attrib.GetItem(index, file2.Attrib); 1800 file2.IsAnti = inDb.IsItemAnti(index); 1801 // file2.IsAux = inDb.IsItemAux(index); 1802} 1803 1804HRESULT Update( 1805 DECL_EXTERNAL_CODECS_LOC_VARS 1806 IInStream *inStream, 1807 const CDbEx *db, 1808 CObjectVector<CUpdateItem> &updateItems, 1809 // const CObjectVector<CTreeFolder> &treeFolders, 1810 // const CUniqBlocks &secureBlocks, 1811 ISequentialOutStream *seqOutStream, 1812 IArchiveUpdateCallback *updateCallback, 1813 const CUpdateOptions &options) 1814{ 1815 UInt64 numSolidFiles = options.NumSolidFiles; 1816 if (numSolidFiles == 0) 1817 numSolidFiles = 1; 1818 1819 Z7_DECL_CMyComPtr_QI_FROM( 1820 IArchiveUpdateCallbackFile, 1821 opCallback, updateCallback) 1822 1823 Z7_DECL_CMyComPtr_QI_FROM( 1824 IArchiveExtractCallbackMessage2, 1825 extractCallback, updateCallback) 1826 1827 /* 1828 Z7_DECL_CMyComPtr_QI_FROM( 1829 IArchiveUpdateCallbackArcProp, 1830 reportArcProp, updateCallback) 1831 */ 1832 1833 // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes(); 1834 1835 CMyComPtr<IStreamSetRestriction> v_StreamSetRestriction; 1836 { 1837 Z7_DECL_CMyComPtr_QI_FROM( 1838 IOutStream, 1839 outStream, seqOutStream) 1840 if (!outStream) 1841 return E_NOTIMPL; 1842 const UInt64 sfxBlockSize = (db && !options.RemoveSfxBlock) ? 1843 db->ArcInfo.StartPosition: 0; 1844 seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&v_StreamSetRestriction); 1845 if (v_StreamSetRestriction) 1846 { 1847 UInt64 offset = 0; 1848 RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &offset)) 1849 RINOK(v_StreamSetRestriction->SetRestriction( 1850 outStream ? offset + sfxBlockSize : 0, 1851 outStream ? offset + sfxBlockSize + k_StartHeadersRewriteSize : 0)) 1852 } 1853 outStream.Release(); 1854 if (sfxBlockSize != 0) 1855 { 1856 RINOK(WriteRange(inStream, seqOutStream, 0, sfxBlockSize, NULL)) 1857 } 1858 } 1859 1860 CIntArr fileIndexToUpdateIndexMap; 1861 UInt64 complexity = 0; 1862 UInt64 inSizeForReduce2 = 0; 1863 1864 #ifndef Z7_NO_CRYPTO 1865 bool needEncryptedRepack = false; 1866 #endif 1867 1868 CRecordVector<CFilterMode2> filters; 1869 CObjectVector<CSolidGroup> groups; 1870 1871 #ifndef Z7_ST 1872 bool thereAreRepacks = false; 1873 #endif 1874 1875 bool useFilters = options.UseFilters; 1876 if (useFilters) 1877 { 1878 const CCompressionMethodMode &method = *options.Method; 1879 1880 FOR_VECTOR (i, method.Methods) 1881 { 1882 /* IsFilterMethod() knows only built-in codecs 1883 FIXME: we should check IsFilter status for external filters too */ 1884 if (IsFilterMethod(method.Methods[i].Id)) 1885 { 1886 useFilters = false; 1887 break; 1888 } 1889 } 1890 } 1891 1892 if (db) 1893 { 1894 fileIndexToUpdateIndexMap.Alloc(db->Files.Size()); 1895 unsigned i; 1896 1897 for (i = 0; i < db->Files.Size(); i++) 1898 fileIndexToUpdateIndexMap[i] = -1; 1899 1900 for (i = 0; i < updateItems.Size(); i++) 1901 { 1902 int index = updateItems[i].IndexInArchive; 1903 if (index != -1) 1904 fileIndexToUpdateIndexMap[(unsigned)index] = (int)i; 1905 } 1906 1907 for (i = 0; i < db->NumFolders; i++) 1908 { 1909 CNum indexInFolder = 0; 1910 CNum numCopyItems = 0; 1911 const CNum numUnpackStreams = db->NumUnpackStreamsVector[i]; 1912 UInt64 repackSize = 0; 1913 1914 for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++) 1915 { 1916 if (fi >= db->Files.Size()) 1917 return E_FAIL; 1918 1919 const CFileItem &file = db->Files[fi]; 1920 if (file.HasStream) 1921 { 1922 indexInFolder++; 1923 const int updateIndex = fileIndexToUpdateIndexMap[fi]; 1924 if (updateIndex >= 0 && !updateItems[(unsigned)updateIndex].NewData) 1925 { 1926 numCopyItems++; 1927 repackSize += file.Size; 1928 } 1929 } 1930 } 1931 1932 if (numCopyItems == 0) 1933 continue; 1934 1935 CFolderRepack rep; 1936 rep.FolderIndex = i; 1937 rep.NumCopyFiles = numCopyItems; 1938 CFolderEx f; 1939 db->ParseFolderEx(i, f); 1940 1941 #ifndef Z7_NO_CRYPTO 1942 const bool isEncrypted = f.IsEncrypted(); 1943 #endif 1944 const bool needCopy = (numCopyItems == numUnpackStreams); 1945 const bool extractFilter = (useFilters || needCopy); 1946 1947 const unsigned groupIndex = Get_FilterGroup_for_Folder(filters, f, extractFilter); 1948 1949 while (groupIndex >= groups.Size()) 1950 groups.AddNew(); 1951 1952 groups[groupIndex].folderRefs.Add(rep); 1953 1954 if (needCopy) 1955 complexity += db->GetFolderFullPackSize(i); 1956 else 1957 { 1958 #ifndef Z7_ST 1959 thereAreRepacks = true; 1960 #endif 1961 complexity += repackSize; 1962 if (inSizeForReduce2 < repackSize) 1963 inSizeForReduce2 = repackSize; 1964 #ifndef Z7_NO_CRYPTO 1965 if (isEncrypted) 1966 needEncryptedRepack = true; 1967 #endif 1968 } 1969 } 1970 } 1971 1972 UInt64 inSizeForReduce = 0; 1973 { 1974 bool isSolid = (numSolidFiles > 1 && options.NumSolidBytes != 0); 1975 FOR_VECTOR (i, updateItems) 1976 { 1977 const CUpdateItem &ui = updateItems[i]; 1978 if (ui.NewData) 1979 { 1980 complexity += ui.Size; 1981 if (isSolid) 1982 inSizeForReduce += ui.Size; 1983 else if (inSizeForReduce < ui.Size) 1984 inSizeForReduce = ui.Size; 1985 } 1986 } 1987 } 1988 1989 if (inSizeForReduce < inSizeForReduce2) 1990 inSizeForReduce = inSizeForReduce2; 1991 1992 RINOK(updateCallback->SetTotal(complexity)) 1993 1994 CLocalProgress *lps = new CLocalProgress; 1995 CMyComPtr<ICompressProgressInfo> progress = lps; 1996 lps->Init(updateCallback, true); 1997 1998 #ifndef Z7_ST 1999 2000 CStreamBinder sb; 2001 /* 2002 if (options.MultiThreadMixer) 2003 { 2004 RINOK(sb.CreateEvents()); 2005 } 2006 */ 2007 2008 #endif 2009 2010 CThreadDecoder threadDecoder(options.MultiThreadMixer); 2011 2012 #ifndef Z7_ST 2013 if (options.MultiThreadMixer && thereAreRepacks) 2014 { 2015 #ifdef Z7_EXTERNAL_CODECS 2016 threadDecoder._externalCodecs = _externalCodecs; 2017 #endif 2018 const WRes wres = threadDecoder.Create(); 2019 if (wres != 0) 2020 return HRESULT_FROM_WIN32(wres); 2021 } 2022 #endif 2023 2024 { 2025 CAnalysis analysis; 2026 // analysis.Need_ATime = options.Need_ATime; 2027 int analysisLevel = options.AnalysisLevel; 2028 // (analysisLevel < 0) means default level (5) 2029 if (analysisLevel < 0) 2030 analysisLevel = 5; 2031 if (analysisLevel != 0) 2032 { 2033 analysis.Callback = opCallback; 2034 analysis.ParseWav = true; 2035 if (analysisLevel >= 5) 2036 { 2037 analysis.ParseExe = true; 2038 analysis.ParseExeUnix = true; 2039 // analysis.ParseNoExt = true; 2040 if (analysisLevel >= 7) 2041 { 2042 analysis.ParseNoExt = true; 2043 if (analysisLevel >= 9) 2044 analysis.ParseAll = true; 2045 } 2046 } 2047 } 2048 2049 // ---------- Split files to groups ---------- 2050 2051 const CCompressionMethodMode &method = *options.Method; 2052 2053 FOR_VECTOR (i, updateItems) 2054 { 2055 const CUpdateItem &ui = updateItems[i]; 2056 if (!ui.NewData || !ui.HasStream()) 2057 continue; 2058 2059 CFilterMode2 fm; 2060 if (useFilters) 2061 { 2062 // analysis.ATime_Defined = false; 2063 RINOK(analysis.GetFilterGroup(i, ui, fm)) 2064 /* 2065 if (analysis.ATime_Defined) 2066 { 2067 ui.ATime = FILETIME_To_UInt64(analysis.ATime); 2068 ui.ATime_WasReadByAnalysis = true; 2069 } 2070 */ 2071 } 2072 fm.Encrypted = method.PasswordIsDefined; 2073 2074 const unsigned groupIndex = GetGroup(filters, fm); 2075 while (groupIndex >= groups.Size()) 2076 groups.AddNew(); 2077 groups[groupIndex].Indices.Add(i); 2078 } 2079 } 2080 2081 2082 #ifndef Z7_NO_CRYPTO 2083 2084 CCryptoGetTextPassword *getPasswordSpec = NULL; 2085 CMyComPtr<ICryptoGetTextPassword> getTextPassword; 2086 if (needEncryptedRepack) 2087 { 2088 getPasswordSpec = new CCryptoGetTextPassword; 2089 getTextPassword = getPasswordSpec; 2090 2091 #ifndef Z7_ST 2092 threadDecoder.getTextPassword = getPasswordSpec; 2093 #endif 2094 2095 if (options.Method->PasswordIsDefined) 2096 getPasswordSpec->Password = options.Method->Password; 2097 else 2098 { 2099 Z7_DECL_CMyComPtr_QI_FROM( 2100 ICryptoGetTextPassword, 2101 getDecoderPassword, updateCallback) 2102 if (!getDecoderPassword) 2103 return E_NOTIMPL; 2104 CMyComBSTR password; 2105 RINOK(getDecoderPassword->CryptoGetTextPassword(&password)) 2106 if (password) 2107 getPasswordSpec->Password = password; 2108 } 2109 } 2110 2111 #endif 2112 2113 // ---------- Compress ---------- 2114 2115 COutArchive archive; 2116 CArchiveDatabaseOut newDatabase; 2117 2118 RINOK(archive.Create_and_WriteStartPrefix(seqOutStream)) 2119 2120 /* 2121 CIntVector treeFolderToArcIndex; 2122 treeFolderToArcIndex.Reserve(treeFolders.Size()); 2123 for (i = 0; i < treeFolders.Size(); i++) 2124 treeFolderToArcIndex.Add(-1); 2125 // ---------- Write Tree (only AUX dirs) ---------- 2126 for (i = 1; i < treeFolders.Size(); i++) 2127 { 2128 const CTreeFolder &treeFolder = treeFolders[i]; 2129 CFileItem file; 2130 CFileItem2 file2; 2131 file2.Init(); 2132 int secureID = 0; 2133 if (treeFolder.UpdateItemIndex < 0) 2134 { 2135 // we can store virtual dir item wuthout attrib, but we want all items have attrib. 2136 file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY); 2137 file2.IsAux = true; 2138 } 2139 else 2140 { 2141 const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex]; 2142 // if item is not dir, then it's parent for alt streams. 2143 // we will write such items later 2144 if (!ui.IsDir) 2145 continue; 2146 secureID = ui.SecureIndex; 2147 if (ui.NewProps) 2148 UpdateItem_To_FileItem(ui, file, file2); 2149 else 2150 GetFile(*db, ui.IndexInArchive, file, file2); 2151 } 2152 file.Size = 0; 2153 file.HasStream = false; 2154 file.IsDir = true; 2155 file.Parent = treeFolder.Parent; 2156 2157 treeFolderToArcIndex[i] = newDatabase.Files.Size(); 2158 newDatabase.AddFile(file, file2, treeFolder.Name); 2159 2160 if (totalSecureDataSize != 0) 2161 newDatabase.SecureIDs.Add(secureID); 2162 } 2163 */ 2164 2165 { 2166 /* ---------- Write non-AUX dirs and Empty files ---------- */ 2167 CUIntVector emptyRefs; 2168 2169 unsigned i; 2170 2171 for (i = 0; i < updateItems.Size(); i++) 2172 { 2173 const CUpdateItem &ui = updateItems[i]; 2174 if (ui.NewData) 2175 { 2176 if (ui.HasStream()) 2177 continue; 2178 } 2179 else if (ui.IndexInArchive != -1 && db->Files[(unsigned)ui.IndexInArchive].HasStream) 2180 continue; 2181 /* 2182 if (ui.TreeFolderIndex >= 0) 2183 continue; 2184 */ 2185 emptyRefs.Add(i); 2186 } 2187 2188 emptyRefs.Sort(CompareEmptyItems, (void *)&updateItems); 2189 2190 for (i = 0; i < emptyRefs.Size(); i++) 2191 { 2192 const CUpdateItem &ui = updateItems[emptyRefs[i]]; 2193 CFileItem file; 2194 CFileItem2 file2; 2195 UString name; 2196 if (ui.NewProps) 2197 { 2198 UpdateItem_To_FileItem(ui, file, file2); 2199 file.CrcDefined = false; 2200 name = ui.Name; 2201 } 2202 else 2203 { 2204 GetFile(*db, (unsigned)ui.IndexInArchive, file, file2); 2205 db->GetPath((unsigned)ui.IndexInArchive, name); 2206 } 2207 2208 /* 2209 if (totalSecureDataSize != 0) 2210 newDatabase.SecureIDs.Add(ui.SecureIndex); 2211 file.Parent = ui.ParentFolderIndex; 2212 */ 2213 newDatabase.AddFile(file, file2, name); 2214 } 2215 } 2216 2217 lps->ProgressOffset = 0; 2218 2219 { 2220 // ---------- Sort Filters ---------- 2221 FOR_VECTOR (i, filters) 2222 { 2223 filters[i].GroupIndex = i; 2224 } 2225 filters.Sort2(); 2226 } 2227 2228 for (unsigned groupIndex = 0; groupIndex < filters.Size(); groupIndex++) 2229 { 2230 const CFilterMode2 &filterMode = filters[groupIndex]; 2231 2232 CCompressionMethodMode method = *options.Method; 2233 { 2234 const HRESULT res = MakeExeMethod(method, filterMode, 2235 #ifdef Z7_ST 2236 false 2237 #else 2238 options.MaxFilter && options.MultiThreadMixer 2239 #endif 2240 ); 2241 2242 RINOK(res) 2243 } 2244 2245 if (filterMode.Encrypted) 2246 { 2247 if (!method.PasswordIsDefined) 2248 { 2249 #ifndef Z7_NO_CRYPTO 2250 if (getPasswordSpec) 2251 method.Password = getPasswordSpec->Password; 2252 #endif 2253 method.PasswordIsDefined = true; 2254 } 2255 } 2256 else 2257 { 2258 method.PasswordIsDefined = false; 2259 method.Password.Empty(); 2260 } 2261 2262 CEncoder encoder(method); 2263 2264 // ---------- Repack and copy old solid blocks ---------- 2265 2266 const CSolidGroup &group = groups[filterMode.GroupIndex]; 2267 2268 FOR_VECTOR (folderRefIndex, group.folderRefs) 2269 { 2270 const CFolderRepack &rep = group.folderRefs[folderRefIndex]; 2271 2272 const unsigned folderIndex = rep.FolderIndex; 2273 2274 const CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex]; 2275 2276 if (rep.NumCopyFiles == numUnpackStreams) 2277 { 2278 if (opCallback) 2279 { 2280 RINOK(opCallback->ReportOperation( 2281 NEventIndexType::kBlockIndex, (UInt32)folderIndex, 2282 NUpdateNotifyOp::kReplicate)) 2283 2284 // ---------- Copy old solid block ---------- 2285 { 2286 CNum indexInFolder = 0; 2287 for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) 2288 { 2289 if (db->Files[fi].HasStream) 2290 { 2291 indexInFolder++; 2292 RINOK(opCallback->ReportOperation( 2293 NEventIndexType::kInArcIndex, (UInt32)fi, 2294 NUpdateNotifyOp::kReplicate)) 2295 } 2296 } 2297 } 2298 } 2299 2300 const UInt64 packSize = db->GetFolderFullPackSize(folderIndex); 2301 RINOK(WriteRange(inStream, archive.SeqStream, 2302 db->GetFolderStreamPos(folderIndex, 0), packSize, progress)) 2303 lps->ProgressOffset += packSize; 2304 2305 const unsigned folderIndex_New = newDatabase.Folders.Size(); 2306 CFolder &folder = newDatabase.Folders.AddNew(); 2307 // v23.01: we copy FolderCrc, if FolderCrc was used 2308 if (db->FolderCRCs.ValidAndDefined(folderIndex)) 2309 newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, 2310 true, db->FolderCRCs.Vals[folderIndex]); 2311 2312 db->ParseFolderInfo(folderIndex, folder); 2313 const CNum startIndex = db->FoStartPackStreamIndex[folderIndex]; 2314 FOR_VECTOR (j, folder.PackStreams) 2315 { 2316 newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j)); 2317 // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]); 2318 // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]); 2319 } 2320 2321 size_t indexStart = db->FoToCoderUnpackSizes[folderIndex]; 2322 const size_t indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1]; 2323 for (; indexStart < indexEnd; indexStart++) 2324 newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]); 2325 } 2326 else 2327 { 2328 // ---------- Repack old solid block ---------- 2329 2330 CBoolVector extractStatuses; 2331 2332 CNum indexInFolder = 0; 2333 2334 if (opCallback) 2335 { 2336 RINOK(opCallback->ReportOperation( 2337 NEventIndexType::kBlockIndex, (UInt32)folderIndex, 2338 NUpdateNotifyOp::kRepack)) 2339 } 2340 2341 /* We could reduce data size of decoded folder, if we don't need to repack 2342 last files in folder. But the gain in speed is small in most cases. 2343 So we unpack full folder. */ 2344 2345 UInt64 sizeToEncode = 0; 2346 2347 /* 2348 UInt64 importantUnpackSize = 0; 2349 unsigned numImportantFiles = 0; 2350 UInt64 decodeSize = 0; 2351 */ 2352 2353 for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) 2354 { 2355 bool needExtract = false; 2356 const CFileItem &file = db->Files[fi]; 2357 2358 if (file.HasStream) 2359 { 2360 indexInFolder++; 2361 const int updateIndex = fileIndexToUpdateIndexMap[fi]; 2362 if (updateIndex >= 0 && !updateItems[(unsigned)updateIndex].NewData) 2363 needExtract = true; 2364 // decodeSize += file.Size; 2365 } 2366 2367 extractStatuses.Add(needExtract); 2368 if (needExtract) 2369 { 2370 sizeToEncode += file.Size; 2371 /* 2372 numImportantFiles = extractStatuses.Size(); 2373 importantUnpackSize = decodeSize; 2374 */ 2375 } 2376 } 2377 2378 // extractStatuses.DeleteFrom(numImportantFiles); 2379 2380 unsigned startPackIndex = newDatabase.PackSizes.Size(); 2381 UInt64 curUnpackSize; 2382 { 2383 CMyComPtr<ISequentialInStream> sbInStream; 2384 CRepackStreamBase *repackBase; 2385 CFolderInStream2 *FosSpec2 = NULL; 2386 2387 CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes; 2388 CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec; 2389 { 2390 #ifndef Z7_ST 2391 if (options.MultiThreadMixer) 2392 { 2393 repackBase = threadDecoder.FosSpec; 2394 CMyComPtr<ISequentialOutStream> sbOutStream; 2395 sb.CreateStreams2(sbInStream, sbOutStream); 2396 RINOK(sb.Create_ReInit()) 2397 2398 threadDecoder.FosSpec->_stream = sbOutStream; 2399 2400 threadDecoder.InStream = inStream; 2401 threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0); 2402 threadDecoder.Folders = (const CFolders *)db; 2403 threadDecoder.FolderIndex = folderIndex; 2404 2405 // threadDecoder.UnpackSize = importantUnpackSize; 2406 // threadDecoder.send_UnpackSize = true; 2407 } 2408 else 2409 #endif 2410 { 2411 FosSpec2 = new CFolderInStream2; 2412 FosSpec2->Init(); 2413 sbInStream = FosSpec2; 2414 repackBase = FosSpec2; 2415 2416 #ifndef Z7_NO_CRYPTO 2417 bool isEncrypted = false; 2418 bool passwordIsDefined = false; 2419 UString password; 2420 #endif 2421 2422 CMyComPtr<ISequentialInStream> decodedStream; 2423 bool dataAfterEnd_Error = false; 2424 2425 const HRESULT res = threadDecoder.Decoder.Decode( 2426 EXTERNAL_CODECS_LOC_VARS 2427 inStream, 2428 db->ArcInfo.DataStartPosition, // db->GetFolderStreamPos(folderIndex, 0);, 2429 *db, folderIndex, 2430 // &importantUnpackSize, // *unpackSize 2431 NULL, // *unpackSize : FULL unpack 2432 2433 NULL, // *outStream 2434 NULL, // *compressProgress 2435 2436 &decodedStream 2437 , dataAfterEnd_Error 2438 2439 Z7_7Z_DECODER_CRYPRO_VARS 2440 #ifndef Z7_ST 2441 , false // mtMode 2442 , 1 // numThreads 2443 , 0 // memUsage 2444 #endif 2445 ); 2446 2447 RINOK(res) 2448 if (!decodedStream) 2449 return E_FAIL; 2450 2451 FosSpec2->_inStream = decodedStream; 2452 } 2453 2454 repackBase->_db = db; 2455 repackBase->_opCallback = opCallback; 2456 repackBase->_extractCallback = extractCallback; 2457 2458 UInt32 startIndex = db->FolderStartFileIndex[folderIndex]; 2459 RINOK(repackBase->Init(startIndex, &extractStatuses)) 2460 2461 inStreamSizeCountSpec->_db = db; 2462 inStreamSizeCountSpec->Init(sbInStream, startIndex, &extractStatuses); 2463 2464 #ifndef Z7_ST 2465 if (options.MultiThreadMixer) 2466 { 2467 WRes wres = threadDecoder.Start(); 2468 if (wres != 0) 2469 return HRESULT_FROM_WIN32(wres); 2470 } 2471 #endif 2472 } 2473 2474 // curUnpackSize = sizeToEncode; 2475 2476 HRESULT encodeRes = encoder.Encode1( 2477 EXTERNAL_CODECS_LOC_VARS 2478 inStreamSizeCount, 2479 // NULL, 2480 &inSizeForReduce, 2481 sizeToEncode, // expectedDataSize 2482 newDatabase.Folders.AddNew(), 2483 // newDatabase.CoderUnpackSizes, curUnpackSize, 2484 archive.SeqStream, newDatabase.PackSizes, progress); 2485 2486 if (encodeRes == k_My_HRESULT_CRC_ERROR) 2487 return E_FAIL; 2488 2489 curUnpackSize = inStreamSizeCountSpec->GetSize(); 2490 2491 if (encodeRes == S_OK) 2492 { 2493 encoder.Encode_Post(curUnpackSize, newDatabase.CoderUnpackSizes); 2494 } 2495 2496 #ifndef Z7_ST 2497 if (options.MultiThreadMixer) 2498 { 2499 // 16.00: hang was fixed : for case if decoding was not finished. 2500 // We close CBinderInStream and it calls CStreamBinder::CloseRead() 2501 inStreamSizeCount.Release(); 2502 sbInStream.Release(); 2503 2504 { 2505 const WRes wres = threadDecoder.WaitExecuteFinish(); 2506 if (wres != 0) 2507 return HRESULT_FROM_WIN32(wres); 2508 } 2509 2510 const HRESULT decodeRes = threadDecoder.Result; 2511 // if (res == k_My_HRESULT_CRC_ERROR) 2512 if (decodeRes == S_FALSE || threadDecoder.dataAfterEnd_Error) 2513 { 2514 if (extractCallback) 2515 { 2516 RINOK(extractCallback->ReportExtractResult( 2517 NEventIndexType::kInArcIndex, db->FolderStartFileIndex[folderIndex], 2518 // NEventIndexType::kBlockIndex, (UInt32)folderIndex, 2519 (decodeRes != S_OK ? 2520 NExtract::NOperationResult::kDataError : 2521 NExtract::NOperationResult::kDataAfterEnd))) 2522 } 2523 if (decodeRes != S_OK) 2524 return E_FAIL; 2525 } 2526 RINOK(decodeRes) 2527 if (encodeRes == S_OK) 2528 if (sb.ProcessedSize != sizeToEncode) 2529 encodeRes = E_FAIL; 2530 } 2531 else 2532 #endif 2533 { 2534 if (FosSpec2->Result == S_FALSE) 2535 { 2536 if (extractCallback) 2537 { 2538 RINOK(extractCallback->ReportExtractResult( 2539 NEventIndexType::kBlockIndex, (UInt32)folderIndex, 2540 NExtract::NOperationResult::kDataError)) 2541 } 2542 return E_FAIL; 2543 } 2544 RINOK(FosSpec2->Result) 2545 } 2546 2547 RINOK(encodeRes) 2548 RINOK(repackBase->CheckFinishedState()) 2549 2550 if (curUnpackSize != sizeToEncode) 2551 return E_FAIL; 2552 } 2553 2554 for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) 2555 lps->OutSize += newDatabase.PackSizes[startPackIndex]; 2556 lps->InSize += curUnpackSize; 2557 } 2558 2559 newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles); 2560 2561 CNum indexInFolder = 0; 2562 for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++) 2563 { 2564 if (db->Files[fi].HasStream) 2565 { 2566 indexInFolder++; 2567 const int updateIndex = fileIndexToUpdateIndexMap[fi]; 2568 if (updateIndex >= 0) 2569 { 2570 const CUpdateItem &ui = updateItems[(unsigned)updateIndex]; 2571 if (ui.NewData) 2572 continue; 2573 2574 UString name; 2575 CFileItem file; 2576 CFileItem2 file2; 2577 GetFile(*db, fi, file, file2); 2578 2579 if (ui.NewProps) 2580 { 2581 UpdateItem_To_FileItem2(ui, file2); 2582 file.IsDir = ui.IsDir; 2583 name = ui.Name; 2584 } 2585 else 2586 db->GetPath(fi, name); 2587 2588 /* 2589 file.Parent = ui.ParentFolderIndex; 2590 if (ui.TreeFolderIndex >= 0) 2591 treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); 2592 if (totalSecureDataSize != 0) 2593 newDatabase.SecureIDs.Add(ui.SecureIndex); 2594 */ 2595 newDatabase.AddFile(file, file2, name); 2596 } 2597 } 2598 } 2599 } 2600 2601 2602 // ---------- Compress files to new solid blocks ---------- 2603 2604 const unsigned numFiles = group.Indices.Size(); 2605 if (numFiles == 0) 2606 continue; 2607 CRecordVector<CRefItem> refItems; 2608 refItems.ClearAndSetSize(numFiles); 2609 // bool sortByType = (options.UseTypeSorting && isSoid); // numSolidFiles > 1 2610 const bool sortByType = options.UseTypeSorting; 2611 2612 unsigned i; 2613 2614 for (i = 0; i < numFiles; i++) 2615 refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType); 2616 2617 CSortParam sortParam; 2618 // sortParam.TreeFolders = &treeFolders; 2619 sortParam.SortByType = sortByType; 2620 refItems.Sort(CompareUpdateItems, (void *)&sortParam); 2621 2622 CObjArray<UInt32> indices(numFiles); 2623 2624 for (i = 0; i < numFiles; i++) 2625 { 2626 const UInt32 index = refItems[i].Index; 2627 indices[i] = index; 2628 /* 2629 const CUpdateItem &ui = updateItems[index]; 2630 CFileItem file; 2631 if (ui.NewProps) 2632 UpdateItem_To_FileItem(ui, file); 2633 else 2634 file = db.Files[ui.IndexInArchive]; 2635 if (file.IsAnti || file.IsDir) 2636 return E_FAIL; 2637 newDatabase.Files.Add(file); 2638 */ 2639 } 2640 2641 for (i = 0; i < numFiles;) 2642 { 2643 UInt64 totalSize = 0; 2644 unsigned numSubFiles; 2645 2646 const wchar_t *prevExtension = NULL; 2647 2648 for (numSubFiles = 0; i + numSubFiles < numFiles && numSubFiles < numSolidFiles; numSubFiles++) 2649 { 2650 const CUpdateItem &ui = updateItems[indices[i + numSubFiles]]; 2651 totalSize += ui.Size; 2652 if (totalSize > options.NumSolidBytes) 2653 break; 2654 if (options.SolidExtension) 2655 { 2656 const int slashPos = ui.Name.ReverseFind_PathSepar(); 2657 const int dotPos = ui.Name.ReverseFind_Dot(); 2658 const wchar_t *ext = ui.Name.Ptr(dotPos <= slashPos ? ui.Name.Len() : (unsigned)(dotPos + 1)); 2659 if (numSubFiles == 0) 2660 prevExtension = ext; 2661 else if (!StringsAreEqualNoCase(ext, prevExtension)) 2662 break; 2663 } 2664 } 2665 2666 if (numSubFiles < 1) 2667 numSubFiles = 1; 2668 2669 RINOK(lps->SetCur()) 2670 2671 /* 2672 const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size(); 2673 2674 if (opCallback) 2675 { 2676 RINOK(opCallback->ReportOperation( 2677 NEventIndexType::kBlockIndex, (UInt32)folderIndex, 2678 NUpdateNotifyOp::kAdd)); 2679 } 2680 */ 2681 2682 2683 CFolderInStream *inStreamSpec = new CFolderInStream; 2684 CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec); 2685 2686 // inStreamSpec->_reportArcProp = reportArcProp; 2687 2688 inStreamSpec->Need_CTime = options.Need_CTime; 2689 inStreamSpec->Need_ATime = options.Need_ATime; 2690 inStreamSpec->Need_MTime = options.Need_MTime; 2691 inStreamSpec->Need_Attrib = options.Need_Attrib; 2692 // inStreamSpec->Need_Crc = options.Need_Crc; 2693 2694 inStreamSpec->Init(updateCallback, &indices[i], numSubFiles); 2695 2696 unsigned startPackIndex = newDatabase.PackSizes.Size(); 2697 // UInt64 curFolderUnpackSize = totalSize; 2698 // curFolderUnpackSize = (UInt64)(Int64)-1; // for debug 2699 const UInt64 expectedDataSize = totalSize; 2700 2701 // const unsigned folderIndex_New = newDatabase.Folders.Size(); 2702 2703 RINOK(encoder.Encode1( 2704 EXTERNAL_CODECS_LOC_VARS 2705 solidInStream, 2706 // NULL, 2707 &inSizeForReduce, 2708 expectedDataSize, // expected size 2709 newDatabase.Folders.AddNew(), 2710 // newDatabase.CoderUnpackSizes, curFolderUnpackSize, 2711 archive.SeqStream, newDatabase.PackSizes, progress)) 2712 2713 if (!inStreamSpec->WasFinished()) 2714 return E_FAIL; 2715 2716 /* 2717 if (inStreamSpec->Need_FolderCrc) 2718 newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, 2719 true, inStreamSpec->GetFolderCrc()); 2720 */ 2721 2722 const UInt64 curFolderUnpackSize = inStreamSpec->Get_TotalSize_for_Coder(); 2723 encoder.Encode_Post(curFolderUnpackSize, newDatabase.CoderUnpackSizes); 2724 2725 UInt64 packSize = 0; 2726 // const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex; 2727 for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++) 2728 packSize += newDatabase.PackSizes[startPackIndex]; 2729 lps->OutSize += packSize; 2730 2731 // for () 2732 // newDatabase.PackCRCsDefined.Add(false); 2733 // newDatabase.PackCRCs.Add(0); 2734 2735 CNum numUnpackStreams = 0; 2736 UInt64 skippedSize = 0; 2737 UInt64 procSize = 0; 2738 // unsigned numProcessedFiles = 0; 2739 2740 for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++) 2741 { 2742 const CUpdateItem &ui = updateItems[indices[i + subIndex]]; 2743 CFileItem file; 2744 CFileItem2 file2; 2745 UString name; 2746 if (ui.NewProps) 2747 { 2748 UpdateItem_To_FileItem(ui, file, file2); 2749 name = ui.Name; 2750 } 2751 else 2752 { 2753 GetFile(*db, (unsigned)ui.IndexInArchive, file, file2); 2754 db->GetPath((unsigned)ui.IndexInArchive, name); 2755 } 2756 if (file2.IsAnti || file.IsDir) 2757 return E_FAIL; 2758 2759 /* 2760 CFileItem &file = newDatabase.Files[ 2761 startFileIndexInDatabase + i + subIndex]; 2762 */ 2763 if (!inStreamSpec->Processed[subIndex]) 2764 { 2765 // we don't add file here 2766 skippedSize += ui.Size; 2767 continue; // comment it for debug 2768 // name += ".locked"; // for debug 2769 } 2770 2771 // if (inStreamSpec->Need_Crc) 2772 file.Crc = inStreamSpec->CRCs[subIndex]; 2773 file.Size = inStreamSpec->Sizes[subIndex]; 2774 2775 procSize += file.Size; 2776 // if (file.Size >= 0) // for debug: test purposes 2777 if (file.Size != 0) 2778 { 2779 file.CrcDefined = true; // inStreamSpec->Need_Crc; 2780 file.HasStream = true; 2781 numUnpackStreams++; 2782 } 2783 else 2784 { 2785 file.CrcDefined = false; 2786 file.HasStream = false; 2787 } 2788 2789 if (inStreamSpec->TimesDefined[subIndex]) 2790 { 2791 if (inStreamSpec->Need_CTime) 2792 { file2.CTimeDefined = true; file2.CTime = inStreamSpec->CTimes[subIndex]; } 2793 if (inStreamSpec->Need_ATime 2794 // && !ui.ATime_WasReadByAnalysis 2795 ) 2796 { file2.ATimeDefined = true; file2.ATime = inStreamSpec->ATimes[subIndex]; } 2797 if (inStreamSpec->Need_MTime) 2798 { file2.MTimeDefined = true; file2.MTime = inStreamSpec->MTimes[subIndex]; } 2799 if (inStreamSpec->Need_Attrib) 2800 { 2801 file2.AttribDefined = true; 2802 file2.Attrib = inStreamSpec->Attribs[subIndex]; 2803 } 2804 } 2805 2806 /* 2807 file.Parent = ui.ParentFolderIndex; 2808 if (ui.TreeFolderIndex >= 0) 2809 treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size(); 2810 if (totalSecureDataSize != 0) 2811 newDatabase.SecureIDs.Add(ui.SecureIndex); 2812 */ 2813 /* 2814 if (reportArcProp) 2815 { 2816 RINOK(ReportItemProps(reportArcProp, ui.IndexInClient, file.Size, 2817 file.CrcDefined ? &file.Crc : NULL)) 2818 } 2819 */ 2820 2821 // numProcessedFiles++; 2822 newDatabase.AddFile(file, file2, name); 2823 } 2824 2825 /* 2826 // for debug: 2827 // we can write crc to folders area, if folder contains only one file 2828 if (numUnpackStreams == 1 && numSubFiles == 1) 2829 { 2830 const CFileItem &file = newDatabase.Files.Back(); 2831 if (file.CrcDefined) 2832 newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, true, file.Crc); 2833 } 2834 */ 2835 2836 /* 2837 // it's optional check to ensure that sizes are correct 2838 if (inStreamSpec->TotalSize_for_Coder != curFolderUnpackSize) 2839 return E_FAIL; 2840 */ 2841 // if (inStreamSpec->AlignLog == 0) 2842 { 2843 if (procSize != curFolderUnpackSize) 2844 return E_FAIL; 2845 } 2846 // else 2847 { 2848 /* 2849 { 2850 const CFolder &old = newDatabase.Folders.Back(); 2851 CFolder &folder = newDatabase.Folders.AddNew(); 2852 { 2853 const unsigned numBonds = old.Bonds.Size(); 2854 folder.Bonds.SetSize(numBonds + 1); 2855 for (unsigned k = 0; k < numBonds; k++) 2856 folder.Bonds[k] = old.Bonds[k]; 2857 CBond &bond = folder.Bonds[numBonds]; 2858 bond.PackIndex = 0; 2859 bond.UnpackIndex = 0; 2860 } 2861 { 2862 const unsigned numCoders = old.Coders.Size(); 2863 folder.Coders.SetSize(numCoders + 1); 2864 for (unsigned k = 0; k < numCoders; k++) 2865 folder.Coders[k] = old.Coders[k]; 2866 CCoderInfo &cod = folder.Coders[numCoders]; 2867 cod.Props.Alloc(1); 2868 cod.Props[0] = (Byte)inStreamSpec->AlignLog; 2869 cod.NumStreams = 1; 2870 } 2871 { 2872 const unsigned numPackStreams = old.Coders.Size(); 2873 folder.Coders.SetSize(numPackStreams); 2874 for (unsigned k = 0; k < numPackStreams; k++) 2875 folder.PackStreams[k] = old.PackStreams[k]; 2876 } 2877 } 2878 newDatabase.Folders.Delete(newDatabase.Folders.Size() - 2); 2879 */ 2880 } 2881 2882 2883 lps->InSize += procSize; 2884 // lps->InSize += curFolderUnpackSize; 2885 2886 // numUnpackStreams = 0 is very bad case for locked files 2887 // v3.13 doesn't understand it. 2888 newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams); 2889 i += numSubFiles; 2890 2891 if (skippedSize != 0 && complexity >= skippedSize) 2892 { 2893 complexity -= skippedSize; 2894 RINOK(updateCallback->SetTotal(complexity)) 2895 } 2896 2897 /* 2898 if (reportArcProp) 2899 { 2900 PROPVARIANT prop; 2901 prop.vt = VT_EMPTY; 2902 prop.wReserved1 = 0; 2903 { 2904 NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numProcessedFiles); 2905 RINOK(reportArcProp->ReportProp( 2906 NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumSubFiles, &prop)); 2907 } 2908 { 2909 NWindows::NCOM::PropVarEm_Set_UInt64(&prop, curFolderUnpackSize); 2910 RINOK(reportArcProp->ReportProp( 2911 NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidSize, &prop)); 2912 } 2913 { 2914 NWindows::NCOM::PropVarEm_Set_UInt64(&prop, packSize); 2915 RINOK(reportArcProp->ReportProp( 2916 NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidPackSize, &prop)); 2917 } 2918 { 2919 NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numStreams); 2920 RINOK(reportArcProp->ReportProp( 2921 NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumStreams, &prop)); 2922 } 2923 RINOK(reportArcProp->ReportFinished(NEventIndexType::kBlockIndex, (UInt32)folderIndex, NUpdate::NOperationResult::kOK)); 2924 } 2925 */ 2926 /* 2927 if (opCallback) 2928 { 2929 RINOK(opCallback->ReportOperation( 2930 NEventIndexType::kBlockIndex, (UInt32)folderIndex, 2931 NUpdateNotifyOp::kOpFinished)); 2932 } 2933 */ 2934 } 2935 } 2936 2937 RINOK(lps->SetCur()) 2938 2939 /* 2940 fileIndexToUpdateIndexMap.ClearAndFree(); 2941 groups.ClearAndFree(); 2942 */ 2943 2944 /* 2945 for (i = 0; i < newDatabase.Files.Size(); i++) 2946 { 2947 CFileItem &file = newDatabase.Files[i]; 2948 file.Parent = treeFolderToArcIndex[file.Parent]; 2949 } 2950 2951 if (totalSecureDataSize != 0) 2952 { 2953 newDatabase.SecureBuf.SetCapacity(totalSecureDataSize); 2954 size_t pos = 0; 2955 newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size()); 2956 for (i = 0; i < secureBlocks.Sorted.Size(); i++) 2957 { 2958 const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]]; 2959 size_t size = buf.GetCapacity(); 2960 if (size != 0) 2961 memcpy(newDatabase.SecureBuf + pos, buf, size); 2962 newDatabase.SecureSizes.Add((UInt32)size); 2963 pos += size; 2964 } 2965 } 2966 */ 2967 2968 { 2969 const unsigned numFolders = newDatabase.Folders.Size(); 2970 if (newDatabase.NumUnpackStreamsVector.Size() != numFolders 2971 || newDatabase.FolderUnpackCRCs.Defs.Size() > numFolders) 2972 return E_FAIL; 2973 newDatabase.FolderUnpackCRCs.if_NonEmpty_FillResedue_with_false(numFolders); 2974 } 2975 2976 updateItems.ClearAndFree(); 2977 newDatabase.ReserveDown(); 2978 2979 if (opCallback) 2980 RINOK(opCallback->ReportOperation(NEventIndexType::kNoIndex, (UInt32)(Int32)-1, NUpdateNotifyOp::kHeader)) 2981 2982 RINOK(archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS 2983 newDatabase, options.HeaderMethod, options.HeaderOptions)) 2984 2985 if (v_StreamSetRestriction) 2986 RINOK(v_StreamSetRestriction->SetRestriction(0, 0)) 2987 2988 return S_OK; 2989} 2990 2991}} 2992