1 // 7zIn.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../../C/7zCrc.h" 6 #include "../../../../C/CpuArch.h" 7 8 #include "../../Common/StreamObjects.h" 9 #include "../../Common/StreamUtils.h" 10 11 #include "7zDecode.h" 12 #include "7zIn.h" 13 14 #define Get16(p) GetUi16(p) 15 #define Get32(p) GetUi32(p) 16 #define Get64(p) GetUi64(p) 17 18 // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader 19 #ifndef _SFX 20 #define FORMAT_7Z_RECOVERY 21 #endif 22 23 namespace NArchive { 24 namespace N7z { 25 26 static void BoolVector_Fill_False(CBoolVector &v, int size) 27 { 28 v.Clear(); 29 v.Reserve(size); 30 for (int i = 0; i < size; i++) 31 v.Add(false); 32 } 33 34 static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index) 35 { 36 if (index >= (UInt32)v.Size()) 37 return true; 38 bool res = v[index]; 39 v[index] = true; 40 return res; 41 } 42 43 bool CFolder::CheckStructure() const 44 { 45 const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it 46 const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax 47 const int kNumBindsMax = 32; 48 49 if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax) 50 return false; 51 52 { 53 CBoolVector v; 54 BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size()); 55 56 int i; 57 for (i = 0; i < BindPairs.Size(); i++) 58 if (BoolVector_GetAndSet(v, BindPairs[i].InIndex)) 59 return false; 60 for (i = 0; i < PackStreams.Size(); i++) 61 if (BoolVector_GetAndSet(v, PackStreams[i])) 62 return false; 63 64 BoolVector_Fill_False(v, UnpackSizes.Size()); 65 for (i = 0; i < BindPairs.Size(); i++) 66 if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex)) 67 return false; 68 } 69 70 UInt32 mask[kMaskSize]; 71 int i; 72 for (i = 0; i < kMaskSize; i++) 73 mask[i] = 0; 74 75 { 76 CIntVector inStreamToCoder, outStreamToCoder; 77 for (i = 0; i < Coders.Size(); i++) 78 { 79 CNum j; 80 const CCoderInfo &coder = Coders[i]; 81 for (j = 0; j < coder.NumInStreams; j++) 82 inStreamToCoder.Add(i); 83 for (j = 0; j < coder.NumOutStreams; j++) 84 outStreamToCoder.Add(i); 85 } 86 87 for (i = 0; i < BindPairs.Size(); i++) 88 { 89 const CBindPair &bp = BindPairs[i]; 90 mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]); 91 } 92 } 93 94 for (i = 0; i < kMaskSize; i++) 95 for (int j = 0; j < kMaskSize; j++) 96 if (((1 << j) & mask[i]) != 0) 97 mask[i] |= mask[j]; 98 99 for (i = 0; i < kMaskSize; i++) 100 if (((1 << i) & mask[i]) != 0) 101 return false; 102 103 return true; 104 } 105 106 class CInArchiveException {}; 107 108 static void ThrowException() { throw CInArchiveException(); } 109 static inline void ThrowEndOfData() { ThrowException(); } 110 static inline void ThrowUnsupported() { ThrowException(); } 111 static inline void ThrowIncorrect() { ThrowException(); } 112 static inline void ThrowUnsupportedVersion() { ThrowException(); } 113 114 /* 115 class CInArchiveException 116 { 117 public: 118 enum CCauseType 119 { 120 kUnsupportedVersion = 0, 121 kUnsupported, 122 kIncorrect, 123 kEndOfData 124 } Cause; 125 CInArchiveException(CCauseType cause): Cause(cause) {}; 126 }; 127 128 static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); } 129 static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); } 130 static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); } 131 static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); } 132 static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); } 133 */ 134 135 class CStreamSwitch 136 { 137 CInArchive *_archive; 138 bool _needRemove; 139 public: 140 CStreamSwitch(): _needRemove(false) {} 141 ~CStreamSwitch() { Remove(); } 142 void Remove(); 143 void Set(CInArchive *archive, const Byte *data, size_t size); 144 void Set(CInArchive *archive, const CByteBuffer &byteBuffer); 145 void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector); 146 }; 147 148 void CStreamSwitch::Remove() 149 { 150 if (_needRemove) 151 { 152 _archive->DeleteByteStream(); 153 _needRemove = false; 154 } 155 } 156 157 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size) 158 { 159 Remove(); 160 _archive = archive; 161 _archive->AddByteStream(data, size); 162 _needRemove = true; 163 } 164 165 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) 166 { 167 Set(archive, byteBuffer, byteBuffer.GetCapacity()); 168 } 169 170 void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector) 171 { 172 Remove(); 173 Byte external = archive->ReadByte(); 174 if (external != 0) 175 { 176 int dataIndex = (int)archive->ReadNum(); 177 if (dataIndex < 0 || dataIndex >= dataVector->Size()) 178 ThrowIncorrect(); 179 Set(archive, (*dataVector)[dataIndex]); 180 } 181 } 182 183 Byte CInByte2::ReadByte() 184 { 185 if (_pos >= _size) 186 ThrowEndOfData(); 187 return _buffer[_pos++]; 188 } 189 190 void CInByte2::ReadBytes(Byte *data, size_t size) 191 { 192 if (size > _size - _pos) 193 ThrowEndOfData(); 194 for (size_t i = 0; i < size; i++) 195 data[i] = _buffer[_pos++]; 196 } 197 198 void CInByte2::SkipData(UInt64 size) 199 { 200 if (size > _size - _pos) 201 ThrowEndOfData(); 202 _pos += (size_t)size; 203 } 204 205 void CInByte2::SkipData() 206 { 207 SkipData(ReadNumber()); 208 } 209 210 UInt64 CInByte2::ReadNumber() 211 { 212 if (_pos >= _size) 213 ThrowEndOfData(); 214 Byte firstByte = _buffer[_pos++]; 215 Byte mask = 0x80; 216 UInt64 value = 0; 217 for (int i = 0; i < 8; i++) 218 { 219 if ((firstByte & mask) == 0) 220 { 221 UInt64 highPart = firstByte & (mask - 1); 222 value += (highPart << (i * 8)); 223 return value; 224 } 225 if (_pos >= _size) 226 ThrowEndOfData(); 227 value |= ((UInt64)_buffer[_pos++] << (8 * i)); 228 mask >>= 1; 229 } 230 return value; 231 } 232 233 CNum CInByte2::ReadNum() 234 { 235 UInt64 value = ReadNumber(); 236 if (value > kNumMax) 237 ThrowUnsupported(); 238 return (CNum)value; 239 } 240 241 UInt32 CInByte2::ReadUInt32() 242 { 243 if (_pos + 4 > _size) 244 ThrowEndOfData(); 245 UInt32 res = Get32(_buffer + _pos); 246 _pos += 4; 247 return res; 248 } 249 250 UInt64 CInByte2::ReadUInt64() 251 { 252 if (_pos + 8 > _size) 253 ThrowEndOfData(); 254 UInt64 res = Get64(_buffer + _pos); 255 _pos += 8; 256 return res; 257 } 258 259 void CInByte2::ReadString(UString &s) 260 { 261 const Byte *buf = _buffer + _pos; 262 size_t rem = (_size - _pos) / 2 * 2; 263 { 264 size_t i; 265 for (i = 0; i < rem; i += 2) 266 if (buf[i] == 0 && buf[i + 1] == 0) 267 break; 268 if (i == rem) 269 ThrowEndOfData(); 270 rem = i; 271 } 272 int len = (int)(rem / 2); 273 if (len < 0 || (size_t)len * 2 != rem) 274 ThrowUnsupported(); 275 wchar_t *p = s.GetBuffer(len); 276 int i; 277 for (i = 0; i < len; i++, buf += 2) 278 p[i] = (wchar_t)Get16(buf); 279 s.ReleaseBuffer(len); 280 _pos += rem + 2; 281 } 282 283 static inline bool TestSignature(const Byte *p) 284 { 285 for (int i = 0; i < kSignatureSize; i++) 286 if (p[i] != kSignature[i]) 287 return false; 288 return CrcCalc(p + 12, 20) == GetUi32(p + 8); 289 } 290 291 #ifdef FORMAT_7Z_RECOVERY 292 static inline bool TestSignature2(const Byte *p) 293 { 294 int i; 295 for (i = 0; i < kSignatureSize; i++) 296 if (p[i] != kSignature[i]) 297 return false; 298 if (CrcCalc(p + 12, 20) == GetUi32(p + 8)) 299 return true; 300 for (i = 8; i < kHeaderSize; i++) 301 if (p[i] != 0) 302 return false; 303 return (p[6] != 0 || p[7] != 0); 304 } 305 #else 306 #define TestSignature2(p) TestSignature(p) 307 #endif 308 309 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 310 { 311 RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)); 312 313 if (TestSignature2(_header)) 314 return S_OK; 315 316 CByteBuffer byteBuffer; 317 const UInt32 kBufferSize = (1 << 16); 318 byteBuffer.SetCapacity(kBufferSize); 319 Byte *buffer = byteBuffer; 320 UInt32 numPrevBytes = kHeaderSize; 321 memcpy(buffer, _header, kHeaderSize); 322 UInt64 curTestPos = _arhiveBeginStreamPosition; 323 for (;;) 324 { 325 if (searchHeaderSizeLimit != NULL) 326 if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit) 327 break; 328 do 329 { 330 UInt32 numReadBytes = kBufferSize - numPrevBytes; 331 UInt32 processedSize; 332 RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize)); 333 numPrevBytes += processedSize; 334 if (processedSize == 0) 335 return S_FALSE; 336 } 337 while (numPrevBytes <= kHeaderSize); 338 UInt32 numTests = numPrevBytes - kHeaderSize; 339 for (UInt32 pos = 0; pos < numTests; pos++) 340 { 341 for (; buffer[pos] != '7' && pos < numTests; pos++); 342 if (pos == numTests) 343 break; 344 if (TestSignature(buffer + pos)) 345 { 346 memcpy(_header, buffer + pos, kHeaderSize); 347 curTestPos += pos; 348 _arhiveBeginStreamPosition = curTestPos; 349 return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL); 350 } 351 } 352 curTestPos += numTests; 353 numPrevBytes -= numTests; 354 memmove(buffer, buffer + numTests, numPrevBytes); 355 } 356 return S_FALSE; 357 } 358 359 // S_FALSE means that file is not archive 360 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 361 { 362 HeadersSize = 0; 363 Close(); 364 RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition)) 365 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); 366 _stream = stream; 367 return S_OK; 368 } 369 370 void CInArchive::Close() 371 { 372 _stream.Release(); 373 } 374 375 void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) 376 { 377 for (;;) 378 { 379 if (ReadID() == NID::kEnd) 380 break; 381 SkipData(); 382 } 383 } 384 385 void CInArchive::GetNextFolderItem(CFolder &folder) 386 { 387 CNum numCoders = ReadNum(); 388 389 folder.Coders.Clear(); 390 folder.Coders.Reserve((int)numCoders); 391 CNum numInStreams = 0; 392 CNum numOutStreams = 0; 393 CNum i; 394 for (i = 0; i < numCoders; i++) 395 { 396 folder.Coders.Add(CCoderInfo()); 397 CCoderInfo &coder = folder.Coders.Back(); 398 399 { 400 Byte mainByte = ReadByte(); 401 int idSize = (mainByte & 0xF); 402 Byte longID[15]; 403 ReadBytes(longID, idSize); 404 if (idSize > 8) 405 ThrowUnsupported(); 406 UInt64 id = 0; 407 for (int j = 0; j < idSize; j++) 408 id |= (UInt64)longID[idSize - 1 - j] << (8 * j); 409 coder.MethodID = id; 410 411 if ((mainByte & 0x10) != 0) 412 { 413 coder.NumInStreams = ReadNum(); 414 coder.NumOutStreams = ReadNum(); 415 } 416 else 417 { 418 coder.NumInStreams = 1; 419 coder.NumOutStreams = 1; 420 } 421 if ((mainByte & 0x20) != 0) 422 { 423 CNum propsSize = ReadNum(); 424 coder.Props.SetCapacity((size_t)propsSize); 425 ReadBytes((Byte *)coder.Props, (size_t)propsSize); 426 } 427 if ((mainByte & 0x80) != 0) 428 ThrowUnsupported(); 429 } 430 numInStreams += coder.NumInStreams; 431 numOutStreams += coder.NumOutStreams; 432 } 433 434 CNum numBindPairs = numOutStreams - 1; 435 folder.BindPairs.Clear(); 436 folder.BindPairs.Reserve(numBindPairs); 437 for (i = 0; i < numBindPairs; i++) 438 { 439 CBindPair bp; 440 bp.InIndex = ReadNum(); 441 bp.OutIndex = ReadNum(); 442 folder.BindPairs.Add(bp); 443 } 444 445 if (numInStreams < numBindPairs) 446 ThrowUnsupported(); 447 CNum numPackStreams = numInStreams - numBindPairs; 448 folder.PackStreams.Reserve(numPackStreams); 449 if (numPackStreams == 1) 450 { 451 for (i = 0; i < numInStreams; i++) 452 if (folder.FindBindPairForInStream(i) < 0) 453 { 454 folder.PackStreams.Add(i); 455 break; 456 } 457 if (folder.PackStreams.Size() != 1) 458 ThrowUnsupported(); 459 } 460 else 461 for (i = 0; i < numPackStreams; i++) 462 folder.PackStreams.Add(ReadNum()); 463 } 464 465 void CInArchive::WaitAttribute(UInt64 attribute) 466 { 467 for (;;) 468 { 469 UInt64 type = ReadID(); 470 if (type == attribute) 471 return; 472 if (type == NID::kEnd) 473 ThrowIncorrect(); 474 SkipData(); 475 } 476 } 477 478 void CInArchive::ReadHashDigests(int numItems, 479 CBoolVector &digestsDefined, 480 CRecordVector<UInt32> &digests) 481 { 482 ReadBoolVector2(numItems, digestsDefined); 483 digests.Clear(); 484 digests.Reserve(numItems); 485 for (int i = 0; i < numItems; i++) 486 { 487 UInt32 crc = 0; 488 if (digestsDefined[i]) 489 crc = ReadUInt32(); 490 digests.Add(crc); 491 } 492 } 493 494 void CInArchive::ReadPackInfo( 495 UInt64 &dataOffset, 496 CRecordVector<UInt64> &packSizes, 497 CBoolVector &packCRCsDefined, 498 CRecordVector<UInt32> &packCRCs) 499 { 500 dataOffset = ReadNumber(); 501 CNum numPackStreams = ReadNum(); 502 503 WaitAttribute(NID::kSize); 504 packSizes.Clear(); 505 packSizes.Reserve(numPackStreams); 506 for (CNum i = 0; i < numPackStreams; i++) 507 packSizes.Add(ReadNumber()); 508 509 UInt64 type; 510 for (;;) 511 { 512 type = ReadID(); 513 if (type == NID::kEnd) 514 break; 515 if (type == NID::kCRC) 516 { 517 ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs); 518 continue; 519 } 520 SkipData(); 521 } 522 if (packCRCsDefined.IsEmpty()) 523 { 524 BoolVector_Fill_False(packCRCsDefined, numPackStreams); 525 packCRCs.Reserve(numPackStreams); 526 packCRCs.Clear(); 527 for (CNum i = 0; i < numPackStreams; i++) 528 packCRCs.Add(0); 529 } 530 } 531 532 void CInArchive::ReadUnpackInfo( 533 const CObjectVector<CByteBuffer> *dataVector, 534 CObjectVector<CFolder> &folders) 535 { 536 WaitAttribute(NID::kFolder); 537 CNum numFolders = ReadNum(); 538 539 { 540 CStreamSwitch streamSwitch; 541 streamSwitch.Set(this, dataVector); 542 folders.Clear(); 543 folders.Reserve(numFolders); 544 for (CNum i = 0; i < numFolders; i++) 545 { 546 folders.Add(CFolder()); 547 GetNextFolderItem(folders.Back()); 548 } 549 } 550 551 WaitAttribute(NID::kCodersUnpackSize); 552 553 CNum i; 554 for (i = 0; i < numFolders; i++) 555 { 556 CFolder &folder = folders[i]; 557 CNum numOutStreams = folder.GetNumOutStreams(); 558 folder.UnpackSizes.Reserve(numOutStreams); 559 for (CNum j = 0; j < numOutStreams; j++) 560 folder.UnpackSizes.Add(ReadNumber()); 561 } 562 563 for (;;) 564 { 565 UInt64 type = ReadID(); 566 if (type == NID::kEnd) 567 return; 568 if (type == NID::kCRC) 569 { 570 CBoolVector crcsDefined; 571 CRecordVector<UInt32> crcs; 572 ReadHashDigests(numFolders, crcsDefined, crcs); 573 for (i = 0; i < numFolders; i++) 574 { 575 CFolder &folder = folders[i]; 576 folder.UnpackCRCDefined = crcsDefined[i]; 577 folder.UnpackCRC = crcs[i]; 578 } 579 continue; 580 } 581 SkipData(); 582 } 583 } 584 585 void CInArchive::ReadSubStreamsInfo( 586 const CObjectVector<CFolder> &folders, 587 CRecordVector<CNum> &numUnpackStreamsInFolders, 588 CRecordVector<UInt64> &unpackSizes, 589 CBoolVector &digestsDefined, 590 CRecordVector<UInt32> &digests) 591 { 592 numUnpackStreamsInFolders.Clear(); 593 numUnpackStreamsInFolders.Reserve(folders.Size()); 594 UInt64 type; 595 for (;;) 596 { 597 type = ReadID(); 598 if (type == NID::kNumUnpackStream) 599 { 600 for (int i = 0; i < folders.Size(); i++) 601 numUnpackStreamsInFolders.Add(ReadNum()); 602 continue; 603 } 604 if (type == NID::kCRC || type == NID::kSize) 605 break; 606 if (type == NID::kEnd) 607 break; 608 SkipData(); 609 } 610 611 if (numUnpackStreamsInFolders.IsEmpty()) 612 for (int i = 0; i < folders.Size(); i++) 613 numUnpackStreamsInFolders.Add(1); 614 615 int i; 616 for (i = 0; i < numUnpackStreamsInFolders.Size(); i++) 617 { 618 // v3.13 incorrectly worked with empty folders 619 // v4.07: we check that folder is empty 620 CNum numSubstreams = numUnpackStreamsInFolders[i]; 621 if (numSubstreams == 0) 622 continue; 623 UInt64 sum = 0; 624 for (CNum j = 1; j < numSubstreams; j++) 625 if (type == NID::kSize) 626 { 627 UInt64 size = ReadNumber(); 628 unpackSizes.Add(size); 629 sum += size; 630 } 631 unpackSizes.Add(folders[i].GetUnpackSize() - sum); 632 } 633 if (type == NID::kSize) 634 type = ReadID(); 635 636 int numDigests = 0; 637 int numDigestsTotal = 0; 638 for (i = 0; i < folders.Size(); i++) 639 { 640 CNum numSubstreams = numUnpackStreamsInFolders[i]; 641 if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) 642 numDigests += numSubstreams; 643 numDigestsTotal += numSubstreams; 644 } 645 646 for (;;) 647 { 648 if (type == NID::kCRC) 649 { 650 CBoolVector digestsDefined2; 651 CRecordVector<UInt32> digests2; 652 ReadHashDigests(numDigests, digestsDefined2, digests2); 653 int digestIndex = 0; 654 for (i = 0; i < folders.Size(); i++) 655 { 656 CNum numSubstreams = numUnpackStreamsInFolders[i]; 657 const CFolder &folder = folders[i]; 658 if (numSubstreams == 1 && folder.UnpackCRCDefined) 659 { 660 digestsDefined.Add(true); 661 digests.Add(folder.UnpackCRC); 662 } 663 else 664 for (CNum j = 0; j < numSubstreams; j++, digestIndex++) 665 { 666 digestsDefined.Add(digestsDefined2[digestIndex]); 667 digests.Add(digests2[digestIndex]); 668 } 669 } 670 } 671 else if (type == NID::kEnd) 672 { 673 if (digestsDefined.IsEmpty()) 674 { 675 BoolVector_Fill_False(digestsDefined, numDigestsTotal); 676 digests.Clear(); 677 for (int i = 0; i < numDigestsTotal; i++) 678 digests.Add(0); 679 } 680 return; 681 } 682 else 683 SkipData(); 684 type = ReadID(); 685 } 686 } 687 688 void CInArchive::ReadStreamsInfo( 689 const CObjectVector<CByteBuffer> *dataVector, 690 UInt64 &dataOffset, 691 CRecordVector<UInt64> &packSizes, 692 CBoolVector &packCRCsDefined, 693 CRecordVector<UInt32> &packCRCs, 694 CObjectVector<CFolder> &folders, 695 CRecordVector<CNum> &numUnpackStreamsInFolders, 696 CRecordVector<UInt64> &unpackSizes, 697 CBoolVector &digestsDefined, 698 CRecordVector<UInt32> &digests) 699 { 700 for (;;) 701 { 702 UInt64 type = ReadID(); 703 if (type > ((UInt32)1 << 30)) 704 ThrowIncorrect(); 705 switch((UInt32)type) 706 { 707 case NID::kEnd: 708 return; 709 case NID::kPackInfo: 710 { 711 ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs); 712 break; 713 } 714 case NID::kUnpackInfo: 715 { 716 ReadUnpackInfo(dataVector, folders); 717 break; 718 } 719 case NID::kSubStreamsInfo: 720 { 721 ReadSubStreamsInfo(folders, numUnpackStreamsInFolders, 722 unpackSizes, digestsDefined, digests); 723 break; 724 } 725 default: 726 ThrowIncorrect(); 727 } 728 } 729 } 730 731 void CInArchive::ReadBoolVector(int numItems, CBoolVector &v) 732 { 733 v.Clear(); 734 v.Reserve(numItems); 735 Byte b = 0; 736 Byte mask = 0; 737 for (int i = 0; i < numItems; i++) 738 { 739 if (mask == 0) 740 { 741 b = ReadByte(); 742 mask = 0x80; 743 } 744 v.Add((b & mask) != 0); 745 mask >>= 1; 746 } 747 } 748 749 void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v) 750 { 751 Byte allAreDefined = ReadByte(); 752 if (allAreDefined == 0) 753 { 754 ReadBoolVector(numItems, v); 755 return; 756 } 757 v.Clear(); 758 v.Reserve(numItems); 759 for (int i = 0; i < numItems; i++) 760 v.Add(true); 761 } 762 763 void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector, 764 CUInt64DefVector &v, int numFiles) 765 { 766 ReadBoolVector2(numFiles, v.Defined); 767 768 CStreamSwitch streamSwitch; 769 streamSwitch.Set(this, &dataVector); 770 v.Values.Reserve(numFiles); 771 772 for (int i = 0; i < numFiles; i++) 773 { 774 UInt64 t = 0; 775 if (v.Defined[i]) 776 t = ReadUInt64(); 777 v.Values.Add(t); 778 } 779 } 780 781 HRESULT CInArchive::ReadAndDecodePackedStreams( 782 DECL_EXTERNAL_CODECS_LOC_VARS 783 UInt64 baseOffset, 784 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector 785 #ifndef _NO_CRYPTO 786 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined 787 #endif 788 ) 789 { 790 CRecordVector<UInt64> packSizes; 791 CBoolVector packCRCsDefined; 792 CRecordVector<UInt32> packCRCs; 793 CObjectVector<CFolder> folders; 794 795 CRecordVector<CNum> numUnpackStreamsInFolders; 796 CRecordVector<UInt64> unpackSizes; 797 CBoolVector digestsDefined; 798 CRecordVector<UInt32> digests; 799 800 ReadStreamsInfo(NULL, 801 dataOffset, 802 packSizes, 803 packCRCsDefined, 804 packCRCs, 805 folders, 806 numUnpackStreamsInFolders, 807 unpackSizes, 808 digestsDefined, 809 digests); 810 811 // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader; 812 813 CNum packIndex = 0; 814 CDecoder decoder( 815 #ifdef _ST_MODE 816 false 817 #else 818 true 819 #endif 820 ); 821 UInt64 dataStartPos = baseOffset + dataOffset; 822 for (int i = 0; i < folders.Size(); i++) 823 { 824 const CFolder &folder = folders[i]; 825 dataVector.Add(CByteBuffer()); 826 CByteBuffer &data = dataVector.Back(); 827 UInt64 unpackSize64 = folder.GetUnpackSize(); 828 size_t unpackSize = (size_t)unpackSize64; 829 if (unpackSize != unpackSize64) 830 ThrowUnsupported(); 831 data.SetCapacity(unpackSize); 832 833 CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; 834 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; 835 outStreamSpec->Init(data, unpackSize); 836 837 HRESULT result = decoder.Decode( 838 EXTERNAL_CODECS_LOC_VARS 839 _stream, dataStartPos, 840 &packSizes[packIndex], folder, outStream, NULL 841 #ifndef _NO_CRYPTO 842 , getTextPassword, passwordIsDefined 843 #endif 844 #if !defined(_7ZIP_ST) && !defined(_SFX) 845 , false, 1 846 #endif 847 ); 848 RINOK(result); 849 850 if (folder.UnpackCRCDefined) 851 if (CrcCalc(data, unpackSize) != folder.UnpackCRC) 852 ThrowIncorrect(); 853 for (int j = 0; j < folder.PackStreams.Size(); j++) 854 { 855 UInt64 packSize = packSizes[packIndex++]; 856 dataStartPos += packSize; 857 HeadersSize += packSize; 858 } 859 } 860 return S_OK; 861 } 862 863 HRESULT CInArchive::ReadHeader( 864 DECL_EXTERNAL_CODECS_LOC_VARS 865 CArchiveDatabaseEx &db 866 #ifndef _NO_CRYPTO 867 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined 868 #endif 869 ) 870 { 871 UInt64 type = ReadID(); 872 873 if (type == NID::kArchiveProperties) 874 { 875 ReadArchiveProperties(db.ArchiveInfo); 876 type = ReadID(); 877 } 878 879 CObjectVector<CByteBuffer> dataVector; 880 881 if (type == NID::kAdditionalStreamsInfo) 882 { 883 HRESULT result = ReadAndDecodePackedStreams( 884 EXTERNAL_CODECS_LOC_VARS 885 db.ArchiveInfo.StartPositionAfterHeader, 886 db.ArchiveInfo.DataStartPosition2, 887 dataVector 888 #ifndef _NO_CRYPTO 889 , getTextPassword, passwordIsDefined 890 #endif 891 ); 892 RINOK(result); 893 db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader; 894 type = ReadID(); 895 } 896 897 CRecordVector<UInt64> unpackSizes; 898 CBoolVector digestsDefined; 899 CRecordVector<UInt32> digests; 900 901 if (type == NID::kMainStreamsInfo) 902 { 903 ReadStreamsInfo(&dataVector, 904 db.ArchiveInfo.DataStartPosition, 905 db.PackSizes, 906 db.PackCRCsDefined, 907 db.PackCRCs, 908 db.Folders, 909 db.NumUnpackStreamsVector, 910 unpackSizes, 911 digestsDefined, 912 digests); 913 db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader; 914 type = ReadID(); 915 } 916 else 917 { 918 for (int i = 0; i < db.Folders.Size(); i++) 919 { 920 db.NumUnpackStreamsVector.Add(1); 921 CFolder &folder = db.Folders[i]; 922 unpackSizes.Add(folder.GetUnpackSize()); 923 digestsDefined.Add(folder.UnpackCRCDefined); 924 digests.Add(folder.UnpackCRC); 925 } 926 } 927 928 db.Files.Clear(); 929 930 if (type == NID::kEnd) 931 return S_OK; 932 if (type != NID::kFilesInfo) 933 ThrowIncorrect(); 934 935 CNum numFiles = ReadNum(); 936 db.Files.Reserve(numFiles); 937 CNum i; 938 for (i = 0; i < numFiles; i++) 939 db.Files.Add(CFileItem()); 940 941 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize); 942 if (!db.PackSizes.IsEmpty()) 943 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo); 944 if (numFiles > 0 && !digests.IsEmpty()) 945 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC); 946 947 CBoolVector emptyStreamVector; 948 BoolVector_Fill_False(emptyStreamVector, (int)numFiles); 949 CBoolVector emptyFileVector; 950 CBoolVector antiFileVector; 951 CNum numEmptyStreams = 0; 952 953 for (;;) 954 { 955 UInt64 type = ReadID(); 956 if (type == NID::kEnd) 957 break; 958 UInt64 size = ReadNumber(); 959 size_t ppp = _inByteBack->_pos; 960 bool addPropIdToList = true; 961 bool isKnownType = true; 962 if (type > ((UInt32)1 << 30)) 963 isKnownType = false; 964 else switch((UInt32)type) 965 { 966 case NID::kName: 967 { 968 CStreamSwitch streamSwitch; 969 streamSwitch.Set(this, &dataVector); 970 for (int i = 0; i < db.Files.Size(); i++) 971 _inByteBack->ReadString(db.Files[i].Name); 972 break; 973 } 974 case NID::kWinAttributes: 975 { 976 CBoolVector boolVector; 977 ReadBoolVector2(db.Files.Size(), boolVector); 978 CStreamSwitch streamSwitch; 979 streamSwitch.Set(this, &dataVector); 980 for (i = 0; i < numFiles; i++) 981 { 982 CFileItem &file = db.Files[i]; 983 file.AttribDefined = boolVector[i]; 984 if (file.AttribDefined) 985 file.Attrib = ReadUInt32(); 986 } 987 break; 988 } 989 case NID::kEmptyStream: 990 { 991 ReadBoolVector(numFiles, emptyStreamVector); 992 for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) 993 if (emptyStreamVector[i]) 994 numEmptyStreams++; 995 996 BoolVector_Fill_False(emptyFileVector, numEmptyStreams); 997 BoolVector_Fill_False(antiFileVector, numEmptyStreams); 998 999 break; 1000 } 1001 case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; 1002 case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; 1003 case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break; 1004 case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break; 1005 case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break; 1006 case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break; 1007 case NID::kDummy: 1008 { 1009 for (UInt64 j = 0; j < size; j++) 1010 if (ReadByte() != 0) 1011 ThrowIncorrect(); 1012 addPropIdToList = false; 1013 break; 1014 } 1015 default: 1016 addPropIdToList = isKnownType = false; 1017 } 1018 if (isKnownType) 1019 { 1020 if(addPropIdToList) 1021 db.ArchiveInfo.FileInfoPopIDs.Add(type); 1022 } 1023 else 1024 SkipData(size); 1025 bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 || 1026 db.ArchiveInfo.Version.Minor > 2); 1027 if (checkRecordsSize && _inByteBack->_pos - ppp != size) 1028 ThrowIncorrect(); 1029 } 1030 1031 CNum emptyFileIndex = 0; 1032 CNum sizeIndex = 0; 1033 1034 CNum numAntiItems = 0; 1035 for (i = 0; i < numEmptyStreams; i++) 1036 if (antiFileVector[i]) 1037 numAntiItems++; 1038 1039 for (i = 0; i < numFiles; i++) 1040 { 1041 CFileItem &file = db.Files[i]; 1042 bool isAnti; 1043 file.HasStream = !emptyStreamVector[i]; 1044 if (file.HasStream) 1045 { 1046 file.IsDir = false; 1047 isAnti = false; 1048 file.Size = unpackSizes[sizeIndex]; 1049 file.Crc = digests[sizeIndex]; 1050 file.CrcDefined = digestsDefined[sizeIndex]; 1051 sizeIndex++; 1052 } 1053 else 1054 { 1055 file.IsDir = !emptyFileVector[emptyFileIndex]; 1056 isAnti = antiFileVector[emptyFileIndex]; 1057 emptyFileIndex++; 1058 file.Size = 0; 1059 file.CrcDefined = false; 1060 } 1061 if (numAntiItems != 0) 1062 db.IsAnti.Add(isAnti); 1063 } 1064 return S_OK; 1065 } 1066 1067 1068 void CArchiveDatabaseEx::FillFolderStartPackStream() 1069 { 1070 FolderStartPackStreamIndex.Clear(); 1071 FolderStartPackStreamIndex.Reserve(Folders.Size()); 1072 CNum startPos = 0; 1073 for (int i = 0; i < Folders.Size(); i++) 1074 { 1075 FolderStartPackStreamIndex.Add(startPos); 1076 startPos += (CNum)Folders[i].PackStreams.Size(); 1077 } 1078 } 1079 1080 void CArchiveDatabaseEx::FillStartPos() 1081 { 1082 PackStreamStartPositions.Clear(); 1083 PackStreamStartPositions.Reserve(PackSizes.Size()); 1084 UInt64 startPos = 0; 1085 for (int i = 0; i < PackSizes.Size(); i++) 1086 { 1087 PackStreamStartPositions.Add(startPos); 1088 startPos += PackSizes[i]; 1089 } 1090 } 1091 1092 void CArchiveDatabaseEx::FillFolderStartFileIndex() 1093 { 1094 FolderStartFileIndex.Clear(); 1095 FolderStartFileIndex.Reserve(Folders.Size()); 1096 FileIndexToFolderIndexMap.Clear(); 1097 FileIndexToFolderIndexMap.Reserve(Files.Size()); 1098 1099 int folderIndex = 0; 1100 CNum indexInFolder = 0; 1101 for (int i = 0; i < Files.Size(); i++) 1102 { 1103 const CFileItem &file = Files[i]; 1104 bool emptyStream = !file.HasStream; 1105 if (emptyStream && indexInFolder == 0) 1106 { 1107 FileIndexToFolderIndexMap.Add(kNumNoIndex); 1108 continue; 1109 } 1110 if (indexInFolder == 0) 1111 { 1112 // v3.13 incorrectly worked with empty folders 1113 // v4.07: Loop for skipping empty folders 1114 for (;;) 1115 { 1116 if (folderIndex >= Folders.Size()) 1117 ThrowIncorrect(); 1118 FolderStartFileIndex.Add(i); // check it 1119 if (NumUnpackStreamsVector[folderIndex] != 0) 1120 break; 1121 folderIndex++; 1122 } 1123 } 1124 FileIndexToFolderIndexMap.Add(folderIndex); 1125 if (emptyStream) 1126 continue; 1127 indexInFolder++; 1128 if (indexInFolder >= NumUnpackStreamsVector[folderIndex]) 1129 { 1130 folderIndex++; 1131 indexInFolder = 0; 1132 } 1133 } 1134 } 1135 1136 HRESULT CInArchive::ReadDatabase2( 1137 DECL_EXTERNAL_CODECS_LOC_VARS 1138 CArchiveDatabaseEx &db 1139 #ifndef _NO_CRYPTO 1140 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined 1141 #endif 1142 ) 1143 { 1144 db.Clear(); 1145 db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition; 1146 1147 db.ArchiveInfo.Version.Major = _header[6]; 1148 db.ArchiveInfo.Version.Minor = _header[7]; 1149 1150 if (db.ArchiveInfo.Version.Major != kMajorVersion) 1151 ThrowUnsupportedVersion(); 1152 1153 UInt32 crcFromArchive = Get32(_header + 8); 1154 UInt64 nextHeaderOffset = Get64(_header + 0xC); 1155 UInt64 nextHeaderSize = Get64(_header + 0x14); 1156 UInt32 nextHeaderCRC = Get32(_header + 0x1C); 1157 UInt32 crc = CrcCalc(_header + 0xC, 20); 1158 1159 #ifdef FORMAT_7Z_RECOVERY 1160 if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) 1161 { 1162 UInt64 cur, cur2; 1163 RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur)); 1164 const int kCheckSize = 500; 1165 Byte buf[kCheckSize]; 1166 RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2)); 1167 int checkSize = kCheckSize; 1168 if (cur2 - cur < kCheckSize) 1169 checkSize = (int)(cur2 - cur); 1170 RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2)); 1171 1172 RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)); 1173 1174 int i; 1175 for (i = (int)checkSize - 2; i >= 0; i--) 1176 if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04) 1177 break; 1178 if (i < 0) 1179 return S_FALSE; 1180 nextHeaderSize = checkSize - i; 1181 nextHeaderOffset = cur2 - cur + i; 1182 nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); 1183 RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL)); 1184 } 1185 else 1186 #endif 1187 { 1188 if (crc != crcFromArchive) 1189 ThrowIncorrect(); 1190 } 1191 1192 db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; 1193 1194 if (nextHeaderSize == 0) 1195 return S_OK; 1196 1197 if (nextHeaderSize > (UInt64)0xFFFFFFFF) 1198 return S_FALSE; 1199 1200 if ((Int64)nextHeaderOffset < 0) 1201 return S_FALSE; 1202 1203 RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL)); 1204 1205 CByteBuffer buffer2; 1206 buffer2.SetCapacity((size_t)nextHeaderSize); 1207 1208 RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize)); 1209 HeadersSize += kHeaderSize + nextHeaderSize; 1210 db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; 1211 1212 if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC) 1213 ThrowIncorrect(); 1214 1215 CStreamSwitch streamSwitch; 1216 streamSwitch.Set(this, buffer2); 1217 1218 CObjectVector<CByteBuffer> dataVector; 1219 1220 UInt64 type = ReadID(); 1221 if (type != NID::kHeader) 1222 { 1223 if (type != NID::kEncodedHeader) 1224 ThrowIncorrect(); 1225 HRESULT result = ReadAndDecodePackedStreams( 1226 EXTERNAL_CODECS_LOC_VARS 1227 db.ArchiveInfo.StartPositionAfterHeader, 1228 db.ArchiveInfo.DataStartPosition2, 1229 dataVector 1230 #ifndef _NO_CRYPTO 1231 , getTextPassword, passwordIsDefined 1232 #endif 1233 ); 1234 RINOK(result); 1235 if (dataVector.Size() == 0) 1236 return S_OK; 1237 if (dataVector.Size() > 1) 1238 ThrowIncorrect(); 1239 streamSwitch.Remove(); 1240 streamSwitch.Set(this, dataVector.Front()); 1241 if (ReadID() != NID::kHeader) 1242 ThrowIncorrect(); 1243 } 1244 1245 db.HeadersSize = HeadersSize; 1246 1247 return ReadHeader( 1248 EXTERNAL_CODECS_LOC_VARS 1249 db 1250 #ifndef _NO_CRYPTO 1251 , getTextPassword, passwordIsDefined 1252 #endif 1253 ); 1254 } 1255 1256 HRESULT CInArchive::ReadDatabase( 1257 DECL_EXTERNAL_CODECS_LOC_VARS 1258 CArchiveDatabaseEx &db 1259 #ifndef _NO_CRYPTO 1260 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined 1261 #endif 1262 ) 1263 { 1264 try 1265 { 1266 return ReadDatabase2( 1267 EXTERNAL_CODECS_LOC_VARS db 1268 #ifndef _NO_CRYPTO 1269 , getTextPassword, passwordIsDefined 1270 #endif 1271 ); 1272 } 1273 catch(CInArchiveException &) { return S_FALSE; } 1274 } 1275 1276 }} 1277