1 // 7zOut.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../../C/7zCrc.h" 6 7 #include "../../../Common/AutoPtr.h" 8 9 #include "../../Common/StreamObjects.h" 10 11 #include "7zOut.h" 12 13 static HRESULT WriteBytes(ISequentialOutStream *stream, const void *data, size_t size) 14 { 15 while (size > 0) 16 { 17 UInt32 curSize = (UInt32)MyMin(size, (size_t)0xFFFFFFFF); 18 UInt32 processedSize; 19 RINOK(stream->Write(data, curSize, &processedSize)); 20 if (processedSize == 0) 21 return E_FAIL; 22 data = (const void *)((const Byte *)data + processedSize); 23 size -= processedSize; 24 } 25 return S_OK; 26 } 27 28 namespace NArchive { 29 namespace N7z { 30 31 HRESULT COutArchive::WriteDirect(const void *data, UInt32 size) 32 { 33 return ::WriteBytes(SeqStream, data, size); 34 } 35 36 HRESULT COutArchive::WriteSignature() 37 { 38 Byte buf[8]; 39 memcpy(buf, kSignature, kSignatureSize); 40 buf[kSignatureSize] = kMajorVersion; 41 buf[kSignatureSize + 1] = 3; 42 return WriteDirect(buf, 8); 43 } 44 45 #ifdef _7Z_VOL 46 HRESULT COutArchive::WriteFinishSignature() 47 { 48 RINOK(WriteDirect(kFinishSignature, kSignatureSize)); 49 CArchiveVersion av; 50 av.Major = kMajorVersion; 51 av.Minor = 2; 52 RINOK(WriteDirectByte(av.Major)); 53 return WriteDirectByte(av.Minor); 54 } 55 #endif 56 57 static void SetUInt32(Byte *p, UInt32 d) 58 { 59 for (int i = 0; i < 4; i++, d >>= 8) 60 p[i] = (Byte)d; 61 } 62 63 static void SetUInt64(Byte *p, UInt64 d) 64 { 65 for (int i = 0; i < 8; i++, d >>= 8) 66 p[i] = (Byte)d; 67 } 68 69 HRESULT COutArchive::WriteStartHeader(const CStartHeader &h) 70 { 71 Byte buf[24]; 72 SetUInt64(buf + 4, h.NextHeaderOffset); 73 SetUInt64(buf + 12, h.NextHeaderSize); 74 SetUInt32(buf + 20, h.NextHeaderCRC); 75 SetUInt32(buf, CrcCalc(buf + 4, 20)); 76 return WriteDirect(buf, 24); 77 } 78 79 #ifdef _7Z_VOL 80 HRESULT COutArchive::WriteFinishHeader(const CFinishHeader &h) 81 { 82 CCRC crc; 83 crc.UpdateUInt64(h.NextHeaderOffset); 84 crc.UpdateUInt64(h.NextHeaderSize); 85 crc.UpdateUInt32(h.NextHeaderCRC); 86 crc.UpdateUInt64(h.ArchiveStartOffset); 87 crc.UpdateUInt64(h.AdditionalStartBlockSize); 88 RINOK(WriteDirectUInt32(crc.GetDigest())); 89 RINOK(WriteDirectUInt64(h.NextHeaderOffset)); 90 RINOK(WriteDirectUInt64(h.NextHeaderSize)); 91 RINOK(WriteDirectUInt32(h.NextHeaderCRC)); 92 RINOK(WriteDirectUInt64(h.ArchiveStartOffset)); 93 return WriteDirectUInt64(h.AdditionalStartBlockSize); 94 } 95 #endif 96 97 HRESULT COutArchive::Create(ISequentialOutStream *stream, bool endMarker) 98 { 99 Close(); 100 #ifdef _7Z_VOL 101 // endMarker = false; 102 _endMarker = endMarker; 103 #endif 104 SeqStream = stream; 105 if (!endMarker) 106 { 107 SeqStream.QueryInterface(IID_IOutStream, &Stream); 108 if (!Stream) 109 { 110 return E_NOTIMPL; 111 // endMarker = true; 112 } 113 } 114 #ifdef _7Z_VOL 115 if (endMarker) 116 { 117 /* 118 CStartHeader sh; 119 sh.NextHeaderOffset = (UInt32)(Int32)-1; 120 sh.NextHeaderSize = (UInt32)(Int32)-1; 121 sh.NextHeaderCRC = 0; 122 WriteStartHeader(sh); 123 */ 124 } 125 else 126 #endif 127 { 128 if (!Stream) 129 return E_FAIL; 130 RINOK(WriteSignature()); 131 RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_prefixHeaderPos)); 132 } 133 return S_OK; 134 } 135 136 void COutArchive::Close() 137 { 138 SeqStream.Release(); 139 Stream.Release(); 140 } 141 142 HRESULT COutArchive::SkipPrefixArchiveHeader() 143 { 144 #ifdef _7Z_VOL 145 if (_endMarker) 146 return S_OK; 147 #endif 148 return Stream->Seek(24, STREAM_SEEK_CUR, NULL); 149 } 150 151 UInt64 COutArchive::GetPos() const 152 { 153 if (_countMode) 154 return _countSize; 155 if (_writeToStream) 156 return _outByte.GetProcessedSize(); 157 return _outByte2.GetPos(); 158 } 159 160 void COutArchive::WriteBytes(const void *data, size_t size) 161 { 162 if (_countMode) 163 _countSize += size; 164 else if (_writeToStream) 165 { 166 _outByte.WriteBytes(data, size); 167 _crc = CrcUpdate(_crc, data, size); 168 } 169 else 170 _outByte2.WriteBytes(data, size); 171 } 172 173 void COutArchive::WriteByte(Byte b) 174 { 175 if (_countMode) 176 _countSize++; 177 else if (_writeToStream) 178 { 179 _outByte.WriteByte(b); 180 _crc = CRC_UPDATE_BYTE(_crc, b); 181 } 182 else 183 _outByte2.WriteByte(b); 184 } 185 186 void COutArchive::WriteUInt32(UInt32 value) 187 { 188 for (int i = 0; i < 4; i++) 189 { 190 WriteByte((Byte)value); 191 value >>= 8; 192 } 193 } 194 195 void COutArchive::WriteUInt64(UInt64 value) 196 { 197 for (int i = 0; i < 8; i++) 198 { 199 WriteByte((Byte)value); 200 value >>= 8; 201 } 202 } 203 204 void COutArchive::WriteNumber(UInt64 value) 205 { 206 Byte firstByte = 0; 207 Byte mask = 0x80; 208 int i; 209 for (i = 0; i < 8; i++) 210 { 211 if (value < ((UInt64(1) << ( 7 * (i + 1))))) 212 { 213 firstByte |= Byte(value >> (8 * i)); 214 break; 215 } 216 firstByte |= mask; 217 mask >>= 1; 218 } 219 WriteByte(firstByte); 220 for (;i > 0; i--) 221 { 222 WriteByte((Byte)value); 223 value >>= 8; 224 } 225 } 226 227 static UInt32 GetBigNumberSize(UInt64 value) 228 { 229 int i; 230 for (i = 1; i < 9; i++) 231 if (value < (((UInt64)1 << (i * 7)))) 232 break; 233 return i; 234 } 235 236 #ifdef _7Z_VOL 237 UInt32 COutArchive::GetVolHeadersSize(UInt64 dataSize, int nameLength, bool props) 238 { 239 UInt32 result = GetBigNumberSize(dataSize) * 2 + 41; 240 if (nameLength != 0) 241 { 242 nameLength = (nameLength + 1) * 2; 243 result += nameLength + GetBigNumberSize(nameLength) + 2; 244 } 245 if (props) 246 { 247 result += 20; 248 } 249 if (result >= 128) 250 result++; 251 result += kSignatureSize + 2 + kFinishHeaderSize; 252 return result; 253 } 254 255 UInt64 COutArchive::GetVolPureSize(UInt64 volSize, int nameLength, bool props) 256 { 257 UInt32 headersSizeBase = COutArchive::GetVolHeadersSize(1, nameLength, props); 258 int testSize; 259 if (volSize > headersSizeBase) 260 testSize = volSize - headersSizeBase; 261 else 262 testSize = 1; 263 UInt32 headersSize = COutArchive::GetVolHeadersSize(testSize, nameLength, props); 264 UInt64 pureSize = 1; 265 if (volSize > headersSize) 266 pureSize = volSize - headersSize; 267 return pureSize; 268 } 269 #endif 270 271 void COutArchive::WriteFolder(const CFolder &folder) 272 { 273 WriteNumber(folder.Coders.Size()); 274 int i; 275 for (i = 0; i < folder.Coders.Size(); i++) 276 { 277 const CCoderInfo &coder = folder.Coders[i]; 278 { 279 size_t propsSize = coder.Props.GetCapacity(); 280 281 UInt64 id = coder.MethodID; 282 int idSize; 283 for (idSize = 1; idSize < sizeof(id); idSize++) 284 if ((id >> (8 * idSize)) == 0) 285 break; 286 BYTE longID[15]; 287 for (int t = idSize - 1; t >= 0 ; t--, id >>= 8) 288 longID[t] = (Byte)(id & 0xFF); 289 Byte b; 290 b = (Byte)(idSize & 0xF); 291 bool isComplex = !coder.IsSimpleCoder(); 292 b |= (isComplex ? 0x10 : 0); 293 b |= ((propsSize != 0) ? 0x20 : 0 ); 294 WriteByte(b); 295 WriteBytes(longID, idSize); 296 if (isComplex) 297 { 298 WriteNumber(coder.NumInStreams); 299 WriteNumber(coder.NumOutStreams); 300 } 301 if (propsSize == 0) 302 continue; 303 WriteNumber(propsSize); 304 WriteBytes(coder.Props, propsSize); 305 } 306 } 307 for (i = 0; i < folder.BindPairs.Size(); i++) 308 { 309 const CBindPair &bindPair = folder.BindPairs[i]; 310 WriteNumber(bindPair.InIndex); 311 WriteNumber(bindPair.OutIndex); 312 } 313 if (folder.PackStreams.Size() > 1) 314 for (i = 0; i < folder.PackStreams.Size(); i++) 315 { 316 WriteNumber(folder.PackStreams[i]); 317 } 318 } 319 320 void COutArchive::WriteBoolVector(const CBoolVector &boolVector) 321 { 322 Byte b = 0; 323 Byte mask = 0x80; 324 for (int i = 0; i < boolVector.Size(); i++) 325 { 326 if (boolVector[i]) 327 b |= mask; 328 mask >>= 1; 329 if (mask == 0) 330 { 331 WriteByte(b); 332 mask = 0x80; 333 b = 0; 334 } 335 } 336 if (mask != 0x80) 337 WriteByte(b); 338 } 339 340 341 void COutArchive::WriteHashDigests( 342 const CRecordVector<bool> &digestsDefined, 343 const CRecordVector<UInt32> &digests) 344 { 345 int numDefined = 0; 346 int i; 347 for (i = 0; i < digestsDefined.Size(); i++) 348 if (digestsDefined[i]) 349 numDefined++; 350 if (numDefined == 0) 351 return; 352 353 WriteByte(NID::kCRC); 354 if (numDefined == digestsDefined.Size()) 355 WriteByte(1); 356 else 357 { 358 WriteByte(0); 359 WriteBoolVector(digestsDefined); 360 } 361 for (i = 0; i < digests.Size(); i++) 362 if (digestsDefined[i]) 363 WriteUInt32(digests[i]); 364 } 365 366 void COutArchive::WritePackInfo( 367 UInt64 dataOffset, 368 const CRecordVector<UInt64> &packSizes, 369 const CRecordVector<bool> &packCRCsDefined, 370 const CRecordVector<UInt32> &packCRCs) 371 { 372 if (packSizes.IsEmpty()) 373 return; 374 WriteByte(NID::kPackInfo); 375 WriteNumber(dataOffset); 376 WriteNumber(packSizes.Size()); 377 WriteByte(NID::kSize); 378 for (int i = 0; i < packSizes.Size(); i++) 379 WriteNumber(packSizes[i]); 380 381 WriteHashDigests(packCRCsDefined, packCRCs); 382 383 WriteByte(NID::kEnd); 384 } 385 386 void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders) 387 { 388 if (folders.IsEmpty()) 389 return; 390 391 WriteByte(NID::kUnpackInfo); 392 393 WriteByte(NID::kFolder); 394 WriteNumber(folders.Size()); 395 { 396 WriteByte(0); 397 for (int i = 0; i < folders.Size(); i++) 398 WriteFolder(folders[i]); 399 } 400 401 WriteByte(NID::kCodersUnpackSize); 402 int i; 403 for (i = 0; i < folders.Size(); i++) 404 { 405 const CFolder &folder = folders[i]; 406 for (int j = 0; j < folder.UnpackSizes.Size(); j++) 407 WriteNumber(folder.UnpackSizes[j]); 408 } 409 410 CRecordVector<bool> unpackCRCsDefined; 411 CRecordVector<UInt32> unpackCRCs; 412 for (i = 0; i < folders.Size(); i++) 413 { 414 const CFolder &folder = folders[i]; 415 unpackCRCsDefined.Add(folder.UnpackCRCDefined); 416 unpackCRCs.Add(folder.UnpackCRC); 417 } 418 WriteHashDigests(unpackCRCsDefined, unpackCRCs); 419 420 WriteByte(NID::kEnd); 421 } 422 423 void COutArchive::WriteSubStreamsInfo( 424 const CObjectVector<CFolder> &folders, 425 const CRecordVector<CNum> &numUnpackStreamsInFolders, 426 const CRecordVector<UInt64> &unpackSizes, 427 const CRecordVector<bool> &digestsDefined, 428 const CRecordVector<UInt32> &digests) 429 { 430 WriteByte(NID::kSubStreamsInfo); 431 432 int i; 433 for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) 434 { 435 if (numUnpackStreamsInFolders[i] != 1) 436 { 437 WriteByte(NID::kNumUnpackStream); 438 for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) 439 WriteNumber(numUnpackStreamsInFolders[i]); 440 break; 441 } 442 } 443 444 445 bool needFlag = true; 446 CNum index = 0; 447 for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) 448 for (CNum j = 0; j < numUnpackStreamsInFolders[i]; j++) 449 { 450 if (j + 1 != numUnpackStreamsInFolders[i]) 451 { 452 if (needFlag) 453 WriteByte(NID::kSize); 454 needFlag = false; 455 WriteNumber(unpackSizes[index]); 456 } 457 index++; 458 } 459 460 CRecordVector<bool> digestsDefined2; 461 CRecordVector<UInt32> digests2; 462 463 int digestIndex = 0; 464 for (i = 0; i < folders.Size(); i++) 465 { 466 int numSubStreams = (int)numUnpackStreamsInFolders[i]; 467 if (numSubStreams == 1 && folders[i].UnpackCRCDefined) 468 digestIndex++; 469 else 470 for (int j = 0; j < numSubStreams; j++, digestIndex++) 471 { 472 digestsDefined2.Add(digestsDefined[digestIndex]); 473 digests2.Add(digests[digestIndex]); 474 } 475 } 476 WriteHashDigests(digestsDefined2, digests2); 477 WriteByte(NID::kEnd); 478 } 479 480 void COutArchive::SkipAlign(unsigned /* pos */, unsigned /* alignSize */) 481 { 482 return; 483 } 484 485 /* 486 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field. 487 488 void COutArchive::SkipAlign(unsigned pos, unsigned alignSize) 489 { 490 pos += (unsigned)GetPos(); 491 pos &= (alignSize - 1); 492 if (pos == 0) 493 return; 494 unsigned skip = alignSize - pos; 495 if (skip < 2) 496 skip += alignSize; 497 skip -= 2; 498 WriteByte(NID::kDummy); 499 WriteByte((Byte)skip); 500 for (unsigned i = 0; i < skip; i++) 501 WriteByte(0); 502 } 503 */ 504 505 static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; } 506 507 void COutArchive::WriteAlignedBoolHeader(const CBoolVector &v, int numDefined, Byte type, unsigned itemSize) 508 { 509 const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v); 510 const UInt64 dataSize = (UInt64)numDefined * itemSize + bvSize + 2; 511 SkipAlign(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSize); 512 513 WriteByte(type); 514 WriteNumber(dataSize); 515 if (numDefined == v.Size()) 516 WriteByte(1); 517 else 518 { 519 WriteByte(0); 520 WriteBoolVector(v); 521 } 522 WriteByte(0); 523 } 524 525 void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type) 526 { 527 int numDefined = 0; 528 529 int i; 530 for (i = 0; i < v.Defined.Size(); i++) 531 if (v.Defined[i]) 532 numDefined++; 533 534 if (numDefined == 0) 535 return; 536 537 WriteAlignedBoolHeader(v.Defined, numDefined, type, 8); 538 539 for (i = 0; i < v.Defined.Size(); i++) 540 if (v.Defined[i]) 541 WriteUInt64(v.Values[i]); 542 } 543 544 HRESULT COutArchive::EncodeStream( 545 DECL_EXTERNAL_CODECS_LOC_VARS 546 CEncoder &encoder, const CByteBuffer &data, 547 CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders) 548 { 549 CBufInStream *streamSpec = new CBufInStream; 550 CMyComPtr<ISequentialInStream> stream = streamSpec; 551 streamSpec->Init(data, data.GetCapacity()); 552 CFolder folderItem; 553 folderItem.UnpackCRCDefined = true; 554 folderItem.UnpackCRC = CrcCalc(data, data.GetCapacity()); 555 UInt64 dataSize64 = data.GetCapacity(); 556 RINOK(encoder.Encode( 557 EXTERNAL_CODECS_LOC_VARS 558 stream, NULL, &dataSize64, folderItem, SeqStream, packSizes, NULL)) 559 folders.Add(folderItem); 560 return S_OK; 561 } 562 563 void COutArchive::WriteHeader( 564 const CArchiveDatabase &db, 565 const CHeaderOptions &headerOptions, 566 UInt64 &headerOffset) 567 { 568 int i; 569 570 UInt64 packedSize = 0; 571 for (i = 0; i < db.PackSizes.Size(); i++) 572 packedSize += db.PackSizes[i]; 573 574 headerOffset = packedSize; 575 576 WriteByte(NID::kHeader); 577 578 // Archive Properties 579 580 if (db.Folders.Size() > 0) 581 { 582 WriteByte(NID::kMainStreamsInfo); 583 WritePackInfo(0, db.PackSizes, 584 db.PackCRCsDefined, 585 db.PackCRCs); 586 587 WriteUnpackInfo(db.Folders); 588 589 CRecordVector<UInt64> unpackSizes; 590 CRecordVector<bool> digestsDefined; 591 CRecordVector<UInt32> digests; 592 for (i = 0; i < db.Files.Size(); i++) 593 { 594 const CFileItem &file = db.Files[i]; 595 if (!file.HasStream) 596 continue; 597 unpackSizes.Add(file.Size); 598 digestsDefined.Add(file.CrcDefined); 599 digests.Add(file.Crc); 600 } 601 602 WriteSubStreamsInfo( 603 db.Folders, 604 db.NumUnpackStreamsVector, 605 unpackSizes, 606 digestsDefined, 607 digests); 608 WriteByte(NID::kEnd); 609 } 610 611 if (db.Files.IsEmpty()) 612 { 613 WriteByte(NID::kEnd); 614 return; 615 } 616 617 WriteByte(NID::kFilesInfo); 618 WriteNumber(db.Files.Size()); 619 620 { 621 /* ---------- Empty Streams ---------- */ 622 CBoolVector emptyStreamVector; 623 emptyStreamVector.Reserve(db.Files.Size()); 624 int numEmptyStreams = 0; 625 for (i = 0; i < db.Files.Size(); i++) 626 if (db.Files[i].HasStream) 627 emptyStreamVector.Add(false); 628 else 629 { 630 emptyStreamVector.Add(true); 631 numEmptyStreams++; 632 } 633 if (numEmptyStreams > 0) 634 { 635 WriteByte(NID::kEmptyStream); 636 WriteNumber(Bv_GetSizeInBytes(emptyStreamVector)); 637 WriteBoolVector(emptyStreamVector); 638 639 CBoolVector emptyFileVector, antiVector; 640 emptyFileVector.Reserve(numEmptyStreams); 641 antiVector.Reserve(numEmptyStreams); 642 CNum numEmptyFiles = 0, numAntiItems = 0; 643 for (i = 0; i < db.Files.Size(); i++) 644 { 645 const CFileItem &file = db.Files[i]; 646 if (!file.HasStream) 647 { 648 emptyFileVector.Add(!file.IsDir); 649 if (!file.IsDir) 650 numEmptyFiles++; 651 bool isAnti = db.IsItemAnti(i); 652 antiVector.Add(isAnti); 653 if (isAnti) 654 numAntiItems++; 655 } 656 } 657 658 if (numEmptyFiles > 0) 659 { 660 WriteByte(NID::kEmptyFile); 661 WriteNumber(Bv_GetSizeInBytes(emptyFileVector)); 662 WriteBoolVector(emptyFileVector); 663 } 664 665 if (numAntiItems > 0) 666 { 667 WriteByte(NID::kAnti); 668 WriteNumber(Bv_GetSizeInBytes(antiVector)); 669 WriteBoolVector(antiVector); 670 } 671 } 672 } 673 674 675 { 676 /* ---------- Names ---------- */ 677 678 int numDefined = 0; 679 size_t namesDataSize = 0; 680 for (int i = 0; i < db.Files.Size(); i++) 681 { 682 const UString &name = db.Files[i].Name; 683 if (!name.IsEmpty()) 684 numDefined++; 685 namesDataSize += (name.Length() + 1) * 2; 686 } 687 688 if (numDefined > 0) 689 { 690 namesDataSize++; 691 SkipAlign(2 + GetBigNumberSize(namesDataSize), 2); 692 693 WriteByte(NID::kName); 694 WriteNumber(namesDataSize); 695 WriteByte(0); 696 for (int i = 0; i < db.Files.Size(); i++) 697 { 698 const UString &name = db.Files[i].Name; 699 for (int t = 0; t <= name.Length(); t++) 700 { 701 wchar_t c = name[t]; 702 WriteByte((Byte)c); 703 WriteByte((Byte)(c >> 8)); 704 } 705 } 706 } 707 } 708 709 if (headerOptions.WriteCTime) WriteUInt64DefVector(db.CTime, NID::kCTime); 710 if (headerOptions.WriteATime) WriteUInt64DefVector(db.ATime, NID::kATime); 711 if (headerOptions.WriteMTime) WriteUInt64DefVector(db.MTime, NID::kMTime); 712 WriteUInt64DefVector(db.StartPos, NID::kStartPos); 713 714 { 715 /* ---------- Write Attrib ---------- */ 716 CBoolVector boolVector; 717 boolVector.Reserve(db.Files.Size()); 718 int numDefined = 0; 719 for (i = 0; i < db.Files.Size(); i++) 720 { 721 bool defined = db.Files[i].AttribDefined; 722 boolVector.Add(defined); 723 if (defined) 724 numDefined++; 725 } 726 if (numDefined > 0) 727 { 728 WriteAlignedBoolHeader(boolVector, numDefined, NID::kWinAttributes, 4); 729 for (i = 0; i < db.Files.Size(); i++) 730 { 731 const CFileItem &file = db.Files[i]; 732 if (file.AttribDefined) 733 WriteUInt32(file.Attrib); 734 } 735 } 736 } 737 738 WriteByte(NID::kEnd); // for files 739 WriteByte(NID::kEnd); // for headers 740 } 741 742 HRESULT COutArchive::WriteDatabase( 743 DECL_EXTERNAL_CODECS_LOC_VARS 744 const CArchiveDatabase &db, 745 const CCompressionMethodMode *options, 746 const CHeaderOptions &headerOptions) 747 { 748 if (!db.CheckNumFiles()) 749 return E_FAIL; 750 751 UInt64 headerOffset; 752 UInt32 headerCRC; 753 UInt64 headerSize; 754 if (db.IsEmpty()) 755 { 756 headerSize = 0; 757 headerOffset = 0; 758 headerCRC = CrcCalc(0, 0); 759 } 760 else 761 { 762 bool encodeHeaders = false; 763 if (options != 0) 764 if (options->IsEmpty()) 765 options = 0; 766 if (options != 0) 767 if (options->PasswordIsDefined || headerOptions.CompressMainHeader) 768 encodeHeaders = true; 769 770 _outByte.SetStream(SeqStream); 771 _outByte.Init(); 772 _crc = CRC_INIT_VAL; 773 _countMode = encodeHeaders; 774 _writeToStream = true; 775 _countSize = 0; 776 WriteHeader(db, headerOptions, headerOffset); 777 778 if (encodeHeaders) 779 { 780 CByteBuffer buf; 781 buf.SetCapacity(_countSize); 782 _outByte2.Init((Byte *)buf, _countSize); 783 784 _countMode = false; 785 _writeToStream = false; 786 WriteHeader(db, headerOptions, headerOffset); 787 788 if (_countSize != _outByte2.GetPos()) 789 return E_FAIL; 790 791 CCompressionMethodMode encryptOptions; 792 encryptOptions.PasswordIsDefined = options->PasswordIsDefined; 793 encryptOptions.Password = options->Password; 794 CEncoder encoder(headerOptions.CompressMainHeader ? *options : encryptOptions); 795 CRecordVector<UInt64> packSizes; 796 CObjectVector<CFolder> folders; 797 RINOK(EncodeStream( 798 EXTERNAL_CODECS_LOC_VARS 799 encoder, buf, 800 packSizes, folders)); 801 802 _writeToStream = true; 803 804 if (folders.Size() == 0) 805 throw 1; 806 807 WriteID(NID::kEncodedHeader); 808 WritePackInfo(headerOffset, packSizes, 809 CRecordVector<bool>(), CRecordVector<UInt32>()); 810 WriteUnpackInfo(folders); 811 WriteByte(NID::kEnd); 812 for (int i = 0; i < packSizes.Size(); i++) 813 headerOffset += packSizes[i]; 814 } 815 RINOK(_outByte.Flush()); 816 headerCRC = CRC_GET_DIGEST(_crc); 817 headerSize = _outByte.GetProcessedSize(); 818 } 819 #ifdef _7Z_VOL 820 if (_endMarker) 821 { 822 CFinishHeader h; 823 h.NextHeaderSize = headerSize; 824 h.NextHeaderCRC = headerCRC; 825 h.NextHeaderOffset = 826 UInt64(0) - (headerSize + 827 4 + kFinishHeaderSize); 828 h.ArchiveStartOffset = h.NextHeaderOffset - headerOffset; 829 h.AdditionalStartBlockSize = 0; 830 RINOK(WriteFinishHeader(h)); 831 return WriteFinishSignature(); 832 } 833 else 834 #endif 835 { 836 CStartHeader h; 837 h.NextHeaderSize = headerSize; 838 h.NextHeaderCRC = headerCRC; 839 h.NextHeaderOffset = headerOffset; 840 RINOK(Stream->Seek(_prefixHeaderPos, STREAM_SEEK_SET, NULL)); 841 return WriteStartHeader(h); 842 } 843 } 844 845 void CArchiveDatabase::GetFile(int index, CFileItem &file, CFileItem2 &file2) const 846 { 847 file = Files[index]; 848 file2.CTimeDefined = CTime.GetItem(index, file2.CTime); 849 file2.ATimeDefined = ATime.GetItem(index, file2.ATime); 850 file2.MTimeDefined = MTime.GetItem(index, file2.MTime); 851 file2.StartPosDefined = StartPos.GetItem(index, file2.StartPos); 852 file2.IsAnti = IsItemAnti(index); 853 } 854 855 void CArchiveDatabase::AddFile(const CFileItem &file, const CFileItem2 &file2) 856 { 857 int index = Files.Size(); 858 CTime.SetItem(index, file2.CTimeDefined, file2.CTime); 859 ATime.SetItem(index, file2.ATimeDefined, file2.ATime); 860 MTime.SetItem(index, file2.MTimeDefined, file2.MTime); 861 StartPos.SetItem(index, file2.StartPosDefined, file2.StartPos); 862 SetItemAnti(index, file2.IsAnti); 863 Files.Add(file); 864 } 865 866 }} 867