1// 7zIn.cpp 2 3#include "StdAfx.h" 4 5#ifdef _WIN32 6#include <wchar.h> 7#else 8#include <ctype.h> 9#endif 10 11#include "../../../../C/7zCrc.h" 12#include "../../../../C/CpuArch.h" 13 14#include "../../../Common/MyBuffer2.h" 15// #include "../../../Common/UTFConvert.h" 16 17#include "../../Common/StreamObjects.h" 18#include "../../Common/StreamUtils.h" 19 20#include "7zDecode.h" 21#include "7zIn.h" 22 23#define Get16(p) GetUi16(p) 24#define Get32(p) GetUi32(p) 25#define Get64(p) GetUi64(p) 26 27// define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader 28#ifndef Z7_SFX 29#define FORMAT_7Z_RECOVERY 30#endif 31 32using namespace NWindows; 33using namespace NCOM; 34 35namespace NArchive { 36namespace N7z { 37 38#define k_Scan_NumCoders_MAX 64 39#define k_Scan_NumCodersStreams_in_Folder_MAX 64 40 41unsigned BoolVector_CountSum(const CBoolVector &v); 42unsigned BoolVector_CountSum(const CBoolVector &v) 43{ 44 unsigned sum = 0; 45 const unsigned size = v.Size(); 46 for (unsigned i = 0; i < size; i++) 47 if (v[i]) 48 sum++; 49 return sum; 50} 51 52static inline bool BoolVector_Item_IsValidAndTrue(const CBoolVector &v, unsigned i) 53{ 54 return (i < v.Size() ? v[i] : false); 55} 56 57static void BoolVector_Fill_False(CBoolVector &v, unsigned size) 58{ 59 v.ClearAndSetSize(size); 60 bool *p = &v[0]; 61 for (unsigned i = 0; i < size; i++) 62 p[i] = false; 63} 64 65 66class CInArchiveException {}; 67class CUnsupportedFeatureException: public CInArchiveException {}; 68 69Z7_ATTR_NORETURN 70static void ThrowException() { throw CInArchiveException(); } 71Z7_ATTR_NORETURN 72static inline void ThrowEndOfData() { ThrowException(); } 73Z7_ATTR_NORETURN 74static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); } 75Z7_ATTR_NORETURN 76static inline void ThrowIncorrect() { ThrowException(); } 77 78class CStreamSwitch 79{ 80 CInArchive *_archive; 81 bool _needRemove; 82 bool _needUpdatePos; 83public: 84 CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {} 85 ~CStreamSwitch() { Remove(); } 86 void Remove(); 87 void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos); 88 void Set(CInArchive *archive, const CByteBuffer &byteBuffer); 89 void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector); 90}; 91 92void CStreamSwitch::Remove() 93{ 94 if (_needRemove) 95 { 96 if (_archive->_inByteBack->GetRem() != 0) 97 _archive->ThereIsHeaderError = true; 98 _archive->DeleteByteStream(_needUpdatePos); 99 _needRemove = false; 100 } 101} 102 103void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos) 104{ 105 Remove(); 106 _archive = archive; 107 _archive->AddByteStream(data, size); 108 _needRemove = true; 109 _needUpdatePos = needUpdatePos; 110} 111 112void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) 113{ 114 Set(archive, byteBuffer, byteBuffer.Size(), false); 115} 116 117void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector) 118{ 119 Remove(); 120 const Byte external = archive->ReadByte(); 121 if (external != 0) 122 { 123 if (!dataVector) 124 ThrowIncorrect(); 125 const CNum dataIndex = archive->ReadNum(); 126 if (dataIndex >= dataVector->Size()) 127 ThrowIncorrect(); 128 Set(archive, (*dataVector)[dataIndex]); 129 } 130} 131 132void CInArchive::AddByteStream(const Byte *buf, size_t size) 133{ 134 if (_numInByteBufs == kNumBufLevelsMax) 135 ThrowIncorrect(); 136 _inByteBack = &_inByteVector[_numInByteBufs++]; 137 _inByteBack->Init(buf, size); 138} 139 140 141Byte CInByte2::ReadByte() 142{ 143 if (_pos >= _size) 144 ThrowEndOfData(); 145 return _buffer[_pos++]; 146} 147 148void CInByte2::ReadBytes(Byte *data, size_t size) 149{ 150 if (size == 0) 151 return; 152 if (size > _size - _pos) 153 ThrowEndOfData(); 154 memcpy(data, _buffer + _pos, size); 155 _pos += size; 156} 157 158void CInByte2::SkipData(UInt64 size) 159{ 160 if (size > _size - _pos) 161 ThrowEndOfData(); 162 _pos += (size_t)size; 163} 164 165void CInByte2::SkipData() 166{ 167 SkipData(ReadNumber()); 168} 169 170static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed) 171{ 172 if (size == 0) 173 { 174 processed = 0; 175 return 0; 176 } 177 178 const unsigned b = *p++; 179 size--; 180 181 if ((b & 0x80) == 0) 182 { 183 processed = 1; 184 return b; 185 } 186 187 if (size == 0) 188 { 189 processed = 0; 190 return 0; 191 } 192 193 UInt64 value = (UInt64)*p; 194 p++; 195 size--; 196 197 for (unsigned i = 1; i < 8; i++) 198 { 199 const unsigned mask = (unsigned)0x80 >> i; 200 if ((b & mask) == 0) 201 { 202 const UInt64 high = b & (mask - 1); 203 value |= (high << (i * 8)); 204 processed = i + 1; 205 return value; 206 } 207 208 if (size == 0) 209 { 210 processed = 0; 211 return 0; 212 } 213 214 value |= ((UInt64)*p << (i * 8)); 215 p++; 216 size--; 217 } 218 219 processed = 9; 220 return value; 221} 222 223UInt64 CInByte2::ReadNumber() 224{ 225 size_t processed; 226 const UInt64 res = ReadNumberSpec(_buffer + _pos, _size - _pos, processed); 227 if (processed == 0) 228 ThrowEndOfData(); 229 _pos += processed; 230 return res; 231} 232 233CNum CInByte2::ReadNum() 234{ 235 /* 236 if (_pos < _size) 237 { 238 Byte val = _buffer[_pos]; 239 if ((unsigned)val < 0x80) 240 { 241 _pos++; 242 return (unsigned)val; 243 } 244 } 245 */ 246 const UInt64 value = ReadNumber(); 247 if (value > kNumMax) 248 ThrowUnsupported(); 249 return (CNum)value; 250} 251 252UInt32 CInByte2::ReadUInt32() 253{ 254 if (_pos + 4 > _size) 255 ThrowEndOfData(); 256 const UInt32 res = Get32(_buffer + _pos); 257 _pos += 4; 258 return res; 259} 260 261UInt64 CInByte2::ReadUInt64() 262{ 263 if (_pos + 8 > _size) 264 ThrowEndOfData(); 265 const UInt64 res = Get64(_buffer + _pos); 266 _pos += 8; 267 return res; 268} 269 270#define Y0 '7' 271#define Y1 'z' 272#define Y2 0xBC 273#define Y3 0xAF 274#define Y4 0x27 275#define Y5 0x1C 276 277#define IS_SIGNATURE(p)( \ 278 (p)[2] == Y2 && \ 279 (p)[3] == Y3 && \ 280 (p)[5] == Y5 && \ 281 (p)[4] == Y4 && \ 282 (p)[1] == Y1 && \ 283 (p)[0] == Y0) 284 285/* FindSignature_10() is allowed to access data up to and including &limit[9]. 286 limit[10] access is not allowed. 287 return: 288 (return_ptr < limit) : signature was found at (return_ptr) 289 (return_ptr >= limit) : limit was reached or crossed. So no signature found before limit 290*/ 291Z7_NO_INLINE 292static const Byte *FindSignature_10(const Byte *p, const Byte *limit) 293{ 294 for (;;) 295 { 296 for (;;) 297 { 298 if (p >= limit) 299 return limit; 300 const Byte b = p[5]; 301 p += 6; 302 if (b == Y0) { break; } 303 if (b == Y1) { p -= 1; break; } 304 if (b == Y2) { p -= 2; break; } 305 if (b == Y3) { p -= 3; break; } 306 if (b == Y4) { p -= 4; break; } 307 if (b == Y5) { p -= 5; break; } 308 } 309 if (IS_SIGNATURE(p - 1)) 310 return p - 1; 311 } 312} 313 314 315static inline bool TestStartCrc(const Byte *p) 316{ 317 return CrcCalc(p + 12, 20) == Get32(p + 8); 318} 319 320static inline bool TestSignature2(const Byte *p) 321{ 322 if (!IS_SIGNATURE(p)) 323 return false; 324 #ifdef FORMAT_7Z_RECOVERY 325 if (TestStartCrc(p)) 326 return true; 327 for (unsigned i = 8; i < kHeaderSize; i++) 328 if (p[i] != 0) 329 return false; 330 return (p[6] != 0 || p[7] != 0); 331 #else 332 return TestStartCrc(p); 333 #endif 334} 335 336 337HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 338{ 339 RINOK(ReadStream_FALSE(stream, _header, kHeaderSize)) 340 341 if (TestSignature2(_header)) 342 return S_OK; 343 if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) 344 return S_FALSE; 345 346 const UInt32 kBufSize = (1 << 15) + kHeaderSize; // must be > (kHeaderSize * 2) 347 CAlignedBuffer1 buf(kBufSize); 348 memcpy(buf, _header, kHeaderSize); 349 UInt64 offset = 0; 350 351 for (;;) 352 { 353 UInt32 readSize = 354 (offset == 0) ? 355 kBufSize - kHeaderSize - kHeaderSize : 356 kBufSize - kHeaderSize; 357 if (searchHeaderSizeLimit) 358 { 359 const UInt64 rem = *searchHeaderSizeLimit - offset; 360 if (readSize > rem) 361 readSize = (UInt32)rem; 362 if (readSize == 0) 363 return S_FALSE; 364 } 365 366 UInt32 processed = 0; 367 RINOK(stream->Read(buf + kHeaderSize, readSize, &processed)) 368 if (processed == 0) 369 return S_FALSE; 370 371 /* &buf[0] was already tested for signature before. 372 So first search here will be for &buf[1] */ 373 374 for (UInt32 pos = 0;;) 375 { 376 const Byte *p = buf + pos + 1; 377 const Byte *lim = buf + processed + 1; 378 /* we have (kHeaderSize - 1 = 31) filled bytes starting from (lim), 379 and it's safe to access just 10 bytes in that reserved area */ 380 p = FindSignature_10(p, lim); 381 if (p >= lim) 382 break; 383 pos = (UInt32)(p - buf); 384 if (TestStartCrc(p)) 385 { 386 memcpy(_header, p, kHeaderSize); 387 _arhiveBeginStreamPosition += offset + pos; 388 return InStream_SeekSet(stream, _arhiveBeginStreamPosition + kHeaderSize); 389 } 390 } 391 392 offset += processed; 393 memmove(buf, buf + processed, kHeaderSize); 394 } 395} 396 397// S_FALSE means that file is not archive 398HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) 399{ 400 HeadersSize = 0; 401 Close(); 402 RINOK(InStream_GetPos_GetSize(stream, _arhiveBeginStreamPosition, _fileEndPosition)) 403 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)) 404 _stream = stream; 405 return S_OK; 406} 407 408void CInArchive::Close() 409{ 410 _numInByteBufs = 0; 411 _stream.Release(); 412 ThereIsHeaderError = false; 413} 414 415void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */) 416{ 417 for (;;) 418 { 419 if (ReadID() == NID::kEnd) 420 break; 421 SkipData(); 422 } 423} 424 425// CFolder &folder can be non empty. So we must set all fields 426 427void CInByte2::ParseFolder(CFolder &folder) 428{ 429 const UInt32 numCoders = ReadNum(); 430 431 if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) 432 ThrowUnsupported(); 433 434 folder.Coders.SetSize(numCoders); 435 436 UInt32 numInStreams = 0; 437 UInt32 i; 438 for (i = 0; i < numCoders; i++) 439 { 440 CCoderInfo &coder = folder.Coders[i]; 441 { 442 const Byte mainByte = ReadByte(); 443 if ((mainByte & 0xC0) != 0) 444 ThrowUnsupported(); 445 const unsigned idSize = (mainByte & 0xF); 446 if (idSize > 8 || idSize > GetRem()) 447 ThrowUnsupported(); 448 const Byte *longID = GetPtr(); 449 UInt64 id = 0; 450 for (unsigned j = 0; j < idSize; j++) 451 id = ((id << 8) | longID[j]); 452 SkipDataNoCheck(idSize); 453 coder.MethodID = id; 454 455 if ((mainByte & 0x10) != 0) 456 { 457 coder.NumStreams = ReadNum(); 458 // if (coder.NumStreams > k_Scan_NumCodersStreams_in_Folder_MAX) ThrowUnsupported(); 459 /* numOutStreams = */ ReadNum(); 460 // if (ReadNum() != 1) // numOutStreams ThrowUnsupported(); 461 } 462 else 463 { 464 coder.NumStreams = 1; 465 } 466 467 if ((mainByte & 0x20) != 0) 468 { 469 const CNum propsSize = ReadNum(); 470 coder.Props.Alloc((size_t)propsSize); 471 ReadBytes((Byte *)coder.Props, (size_t)propsSize); 472 } 473 else 474 coder.Props.Free(); 475 } 476 numInStreams += coder.NumStreams; 477 } 478 479 const UInt32 numBonds = numCoders - 1; 480 folder.Bonds.SetSize(numBonds); 481 for (i = 0; i < numBonds; i++) 482 { 483 CBond &bp = folder.Bonds[i]; 484 bp.PackIndex = ReadNum(); 485 bp.UnpackIndex = ReadNum(); 486 } 487 488 if (numInStreams < numBonds) 489 ThrowUnsupported(); 490 const UInt32 numPackStreams = numInStreams - numBonds; 491 folder.PackStreams.SetSize(numPackStreams); 492 493 if (numPackStreams == 1) 494 { 495 for (i = 0; i < numInStreams; i++) 496 if (folder.FindBond_for_PackStream(i) < 0) 497 { 498 folder.PackStreams[0] = i; 499 break; 500 } 501 if (i == numInStreams) 502 ThrowUnsupported(); 503 } 504 else 505 for (i = 0; i < numPackStreams; i++) 506 folder.PackStreams[i] = ReadNum(); 507} 508 509void CFolders::ParseFolderInfo(unsigned folderIndex, CFolder &folder) const 510{ 511 const size_t startPos = FoCodersDataOffset[folderIndex]; 512 CInByte2 inByte; 513 inByte.Init(CodersData + startPos, FoCodersDataOffset[folderIndex + 1] - startPos); 514 inByte.ParseFolder(folder); 515 if (inByte.GetRem() != 0) 516 throw 20120424; 517} 518 519 520void CDatabase::GetPath(unsigned index, UString &path) const 521{ 522 path.Empty(); 523 if (!NameOffsets || !NamesBuf) 524 return; 525 526 const size_t offset = NameOffsets[index]; 527 const size_t size = NameOffsets[index + 1] - offset; 528 529 if (size >= (1 << 28)) 530 return; 531 532 wchar_t *s = path.GetBuf((unsigned)size - 1); 533 534 const Byte *p = ((const Byte *)NamesBuf + offset * 2); 535 536 #if defined(_WIN32) && defined(MY_CPU_LE) 537 538 wmemcpy(s, (const wchar_t *)(const void *)p, size); 539 540 #else 541 542 for (size_t i = 0; i < size; i++) 543 { 544 *s = Get16(p); 545 p += 2; 546 s++; 547 } 548 549 #endif 550 551 path.ReleaseBuf_SetLen((unsigned)size - 1); 552} 553 554HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw() 555{ 556 PropVariant_Clear(path); 557 if (!NameOffsets || !NamesBuf) 558 return S_OK; 559 560 const size_t offset = NameOffsets[index]; 561 const size_t size = NameOffsets[index + 1] - offset; 562 563 if (size >= (1 << 14)) 564 return S_OK; 565 566 // (size) includes null terminator 567 568 /* 569 #if WCHAR_MAX > 0xffff 570 571 const Byte *p = ((const Byte *)NamesBuf + offset * 2); 572 size = Utf16LE__Get_Num_WCHARs(p, size - 1); 573 // (size) doesn't include null terminator 574 RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size)); 575 wchar_t *s = path->bstrVal; 576 wchar_t *sEnd = Utf16LE__To_WCHARs_Sep(p, size, s); 577 *sEnd = 0; 578 if (s + size != sEnd) return E_FAIL; 579 580 #else 581 */ 582 583 RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size - 1)) 584 wchar_t *s = path->bstrVal; 585 const Byte *p = ((const Byte *)NamesBuf + offset * 2); 586 // Utf16LE__To_WCHARs_Sep(p, size, s); 587 588 for (size_t i = 0; i < size; i++) 589 { 590 wchar_t c = Get16(p); 591 p += 2; 592 #if WCHAR_PATH_SEPARATOR != L'/' 593 if (c == L'/') 594 c = WCHAR_PATH_SEPARATOR; 595 else if (c == L'\\') 596 c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme 597 #endif 598 *s++ = c; 599 } 600 601 // #endif 602 603 return S_OK; 604 605 /* 606 unsigned cur = index; 607 unsigned size = 0; 608 609 for (int i = 0;; i++) 610 { 611 size_t len = NameOffsets[cur + 1] - NameOffsets[cur]; 612 size += (unsigned)len; 613 if (i > 256 || len > (1 << 14) || size > (1 << 14)) 614 return PropVarEm_Set_Str(path, "[TOO-LONG]"); 615 cur = Files[cur].Parent; 616 if (cur < 0) 617 break; 618 } 619 size--; 620 621 RINOK(PropVarEm_Alloc_Bstr(path, size)); 622 wchar_t *s = path->bstrVal; 623 s += size; 624 *s = 0; 625 cur = index; 626 627 for (;;) 628 { 629 unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1); 630 const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2; 631 for (; len != 0; len--) 632 { 633 p -= 2; 634 --s; 635 wchar_t c = Get16(p); 636 if (c == '/') 637 c = WCHAR_PATH_SEPARATOR; 638 *s = c; 639 } 640 641 const CFileItem &file = Files[cur]; 642 cur = file.Parent; 643 if (cur < 0) 644 return S_OK; 645 *(--s) = (file.IsAltStream ? ':' : WCHAR_PATH_SEPARATOR); 646 } 647 */ 648} 649 650void CInArchive::WaitId(UInt64 id) 651{ 652 for (;;) 653 { 654 const UInt64 type = ReadID(); 655 if (type == id) 656 return; 657 if (type == NID::kEnd) 658 ThrowIncorrect(); 659 SkipData(); 660 } 661} 662 663 664void CInArchive::Read_UInt32_Vector(CUInt32DefVector &v) 665{ 666 const unsigned numItems = v.Defs.Size(); 667 v.Vals.ClearAndSetSize(numItems); 668 UInt32 *p = &v.Vals[0]; 669 const bool *defs = &v.Defs[0]; 670 for (unsigned i = 0; i < numItems; i++) 671 { 672 UInt32 a = 0; 673 if (defs[i]) 674 a = ReadUInt32(); 675 p[i] = a; 676 } 677} 678 679 680void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs) 681{ 682 ReadBoolVector2(numItems, crcs.Defs); 683 Read_UInt32_Vector(crcs); 684} 685 686 687void CInArchive::ReadPackInfo(CFolders &f) 688{ 689 const CNum numPackStreams = ReadNum(); 690 691 WaitId(NID::kSize); 692 f.PackPositions.Alloc(numPackStreams + 1); 693 f.NumPackStreams = numPackStreams; 694 UInt64 sum = 0; 695 for (CNum i = 0; i < numPackStreams; i++) 696 { 697 f.PackPositions[i] = sum; 698 const UInt64 packSize = ReadNumber(); 699 sum += packSize; 700 if (sum < packSize) 701 ThrowIncorrect(); 702 } 703 f.PackPositions[numPackStreams] = sum; 704 705 UInt64 type; 706 for (;;) 707 { 708 type = ReadID(); 709 if (type == NID::kEnd) 710 return; 711 if (type == NID::kCRC) 712 { 713 CUInt32DefVector PackCRCs; 714 ReadHashDigests(numPackStreams, PackCRCs); 715 continue; 716 } 717 SkipData(); 718 } 719} 720 721void CInArchive::ReadUnpackInfo( 722 const CObjectVector<CByteBuffer> *dataVector, 723 CFolders &folders) 724{ 725 WaitId(NID::kFolder); 726 const CNum numFolders = ReadNum(); 727 728 CNum numCodersOutStreams = 0; 729 { 730 CStreamSwitch streamSwitch; 731 streamSwitch.Set(this, dataVector); 732 const Byte *startBufPtr = _inByteBack->GetPtr(); 733 folders.NumFolders = numFolders; 734 735 folders.FoStartPackStreamIndex.Alloc(numFolders + 1); 736 folders.FoToMainUnpackSizeIndex.Alloc(numFolders); 737 folders.FoCodersDataOffset.Alloc(numFolders + 1); 738 folders.FoToCoderUnpackSizes.Alloc(numFolders + 1); 739 740 CBoolVector StreamUsed; 741 CBoolVector CoderUsed; 742 743 CNum packStreamIndex = 0; 744 CNum fo; 745 CInByte2 *inByte = _inByteBack; 746 747 for (fo = 0; fo < numFolders; fo++) 748 { 749 UInt32 indexOfMainStream = 0; 750 UInt32 numPackStreams = 0; 751 folders.FoCodersDataOffset[fo] = (size_t)(_inByteBack->GetPtr() - startBufPtr); 752 753 CNum numInStreams = 0; 754 const CNum numCoders = inByte->ReadNum(); 755 756 if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX) 757 ThrowUnsupported(); 758 759 for (CNum ci = 0; ci < numCoders; ci++) 760 { 761 const Byte mainByte = inByte->ReadByte(); 762 if ((mainByte & 0xC0) != 0) 763 ThrowUnsupported(); 764 765 const unsigned idSize = (mainByte & 0xF); 766 if (idSize > 8) 767 ThrowUnsupported(); 768 if (idSize > inByte->GetRem()) 769 ThrowEndOfData(); 770 const Byte *longID = inByte->GetPtr(); 771 UInt64 id = 0; 772 for (unsigned j = 0; j < idSize; j++) 773 id = ((id << 8) | longID[j]); 774 inByte->SkipDataNoCheck(idSize); 775 if (folders.ParsedMethods.IDs.Size() < 128) 776 folders.ParsedMethods.IDs.AddToUniqueSorted(id); 777 778 CNum coderInStreams = 1; 779 if ((mainByte & 0x10) != 0) 780 { 781 coderInStreams = inByte->ReadNum(); 782 if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) 783 ThrowUnsupported(); 784 if (inByte->ReadNum() != 1) 785 ThrowUnsupported(); 786 } 787 788 numInStreams += coderInStreams; 789 if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX) 790 ThrowUnsupported(); 791 792 if ((mainByte & 0x20) != 0) 793 { 794 const CNum propsSize = inByte->ReadNum(); 795 if (propsSize > inByte->GetRem()) 796 ThrowEndOfData(); 797 if (id == k_LZMA2 && propsSize == 1) 798 { 799 const Byte v = *_inByteBack->GetPtr(); 800 if (folders.ParsedMethods.Lzma2Prop < v) 801 folders.ParsedMethods.Lzma2Prop = v; 802 } 803 else if (id == k_LZMA && propsSize == 5) 804 { 805 const UInt32 dicSize = GetUi32(_inByteBack->GetPtr() + 1); 806 if (folders.ParsedMethods.LzmaDic < dicSize) 807 folders.ParsedMethods.LzmaDic = dicSize; 808 } 809 inByte->SkipDataNoCheck((size_t)propsSize); 810 } 811 } 812 813 if (numCoders == 1 && numInStreams == 1) 814 { 815 indexOfMainStream = 0; 816 numPackStreams = 1; 817 } 818 else 819 { 820 UInt32 i; 821 const CNum numBonds = numCoders - 1; 822 if (numInStreams < numBonds) 823 ThrowUnsupported(); 824 825 BoolVector_Fill_False(StreamUsed, numInStreams); 826 BoolVector_Fill_False(CoderUsed, numCoders); 827 828 for (i = 0; i < numBonds; i++) 829 { 830 CNum index = ReadNum(); 831 if (index >= numInStreams || StreamUsed[index]) 832 ThrowUnsupported(); 833 StreamUsed[index] = true; 834 835 index = ReadNum(); 836 if (index >= numCoders || CoderUsed[index]) 837 ThrowUnsupported(); 838 CoderUsed[index] = true; 839 } 840 841 numPackStreams = numInStreams - numBonds; 842 843 if (numPackStreams != 1) 844 for (i = 0; i < numPackStreams; i++) 845 { 846 const CNum index = inByte->ReadNum(); // PackStreams 847 if (index >= numInStreams || StreamUsed[index]) 848 ThrowUnsupported(); 849 StreamUsed[index] = true; 850 } 851 852 for (i = 0; i < numCoders; i++) 853 if (!CoderUsed[i]) 854 { 855 indexOfMainStream = i; 856 break; 857 } 858 859 if (i == numCoders) 860 ThrowUnsupported(); 861 } 862 863 folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; 864 numCodersOutStreams += numCoders; 865 folders.FoStartPackStreamIndex[fo] = packStreamIndex; 866 if (numPackStreams > folders.NumPackStreams - packStreamIndex) 867 ThrowIncorrect(); 868 packStreamIndex += numPackStreams; 869 folders.FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream; 870 } 871 872 const size_t dataSize = (size_t)(_inByteBack->GetPtr() - startBufPtr); 873 folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams; 874 folders.FoStartPackStreamIndex[fo] = packStreamIndex; 875 folders.FoCodersDataOffset[fo] = (size_t)(_inByteBack->GetPtr() - startBufPtr); 876 folders.CodersData.CopyFrom(startBufPtr, dataSize); 877 878 // if (folders.NumPackStreams != packStreamIndex) ThrowUnsupported(); 879 } 880 881 WaitId(NID::kCodersUnpackSize); 882 folders.CoderUnpackSizes.Alloc(numCodersOutStreams); 883 for (CNum i = 0; i < numCodersOutStreams; i++) 884 folders.CoderUnpackSizes[i] = ReadNumber(); 885 886 for (;;) 887 { 888 const UInt64 type = ReadID(); 889 if (type == NID::kEnd) 890 return; 891 if (type == NID::kCRC) 892 { 893 ReadHashDigests(numFolders, folders.FolderCRCs); 894 continue; 895 } 896 SkipData(); 897 } 898} 899 900void CInArchive::ReadSubStreamsInfo( 901 CFolders &folders, 902 CRecordVector<UInt64> &unpackSizes, 903 CUInt32DefVector &digests) 904{ 905 folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); 906 CNum i; 907 for (i = 0; i < folders.NumFolders; i++) 908 folders.NumUnpackStreamsVector[i] = 1; 909 910 UInt64 type; 911 912 for (;;) 913 { 914 type = ReadID(); 915 if (type == NID::kNumUnpackStream) 916 { 917 for (i = 0; i < folders.NumFolders; i++) 918 folders.NumUnpackStreamsVector[i] = ReadNum(); 919 continue; 920 } 921 if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd) 922 break; 923 SkipData(); 924 } 925 926 if (type == NID::kSize) 927 { 928 for (i = 0; i < folders.NumFolders; i++) 929 { 930 // v3.13 incorrectly worked with empty folders 931 // v4.07: we check that folder is empty 932 const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; 933 if (numSubstreams == 0) 934 continue; 935 UInt64 sum = 0; 936 for (CNum j = 1; j < numSubstreams; j++) 937 { 938 const UInt64 size = ReadNumber(); 939 unpackSizes.Add(size); 940 sum += size; 941 if (sum < size) 942 ThrowIncorrect(); 943 } 944 const UInt64 folderUnpackSize = folders.GetFolderUnpackSize(i); 945 if (folderUnpackSize < sum) 946 ThrowIncorrect(); 947 unpackSizes.Add(folderUnpackSize - sum); 948 } 949 type = ReadID(); 950 } 951 else 952 { 953 for (i = 0; i < folders.NumFolders; i++) 954 { 955 /* v9.26 - v9.29 incorrectly worked: 956 if (folders.NumUnpackStreamsVector[i] == 0), it threw error */ 957 const CNum val = folders.NumUnpackStreamsVector[i]; 958 if (val > 1) 959 ThrowIncorrect(); 960 if (val == 1) 961 unpackSizes.Add(folders.GetFolderUnpackSize(i)); 962 } 963 } 964 965 unsigned numDigests = 0; 966 for (i = 0; i < folders.NumFolders; i++) 967 { 968 const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; 969 if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i)) 970 numDigests += numSubstreams; 971 } 972 973 for (;;) 974 { 975 if (type == NID::kEnd) 976 break; 977 if (type == NID::kCRC) 978 { 979 // CUInt32DefVector digests2; 980 // ReadHashDigests(numDigests, digests2); 981 CBoolVector digests2; 982 ReadBoolVector2(numDigests, digests2); 983 984 digests.ClearAndSetSize(unpackSizes.Size()); 985 986 unsigned k = 0; 987 unsigned k2 = 0; 988 989 for (i = 0; i < folders.NumFolders; i++) 990 { 991 const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; 992 if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) 993 { 994 digests.Defs[k] = true; 995 digests.Vals[k] = folders.FolderCRCs.Vals[i]; 996 k++; 997 } 998 else for (CNum j = 0; j < numSubstreams; j++) 999 { 1000 bool defined = digests2[k2++]; 1001 digests.Defs[k] = defined; 1002 UInt32 crc = 0; 1003 if (defined) 1004 crc = ReadUInt32(); 1005 digests.Vals[k] = crc; 1006 k++; 1007 } 1008 } 1009 // if (k != unpackSizes.Size()) throw 1234567; 1010 } 1011 else 1012 SkipData(); 1013 1014 type = ReadID(); 1015 } 1016 1017 if (digests.Defs.Size() != unpackSizes.Size()) 1018 { 1019 digests.ClearAndSetSize(unpackSizes.Size()); 1020 unsigned k = 0; 1021 for (i = 0; i < folders.NumFolders; i++) 1022 { 1023 const CNum numSubstreams = folders.NumUnpackStreamsVector[i]; 1024 if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i)) 1025 { 1026 digests.Defs[k] = true; 1027 digests.Vals[k] = folders.FolderCRCs.Vals[i]; 1028 k++; 1029 } 1030 else for (CNum j = 0; j < numSubstreams; j++) 1031 { 1032 digests.Defs[k] = false; 1033 digests.Vals[k] = 0; 1034 k++; 1035 } 1036 } 1037 } 1038} 1039 1040 1041 1042void CInArchive::ReadStreamsInfo( 1043 const CObjectVector<CByteBuffer> *dataVector, 1044 UInt64 &dataOffset, 1045 CFolders &folders, 1046 CRecordVector<UInt64> &unpackSizes, 1047 CUInt32DefVector &digests) 1048{ 1049 UInt64 type = ReadID(); 1050 1051 if (type == NID::kPackInfo) 1052 { 1053 dataOffset = ReadNumber(); 1054 if (dataOffset > _rangeLimit) 1055 ThrowIncorrect(); 1056 ReadPackInfo(folders); 1057 if (folders.PackPositions[folders.NumPackStreams] > _rangeLimit - dataOffset) 1058 ThrowIncorrect(); 1059 type = ReadID(); 1060 } 1061 1062 if (type == NID::kUnpackInfo) 1063 { 1064 ReadUnpackInfo(dataVector, folders); 1065 type = ReadID(); 1066 } 1067 1068 if (folders.NumFolders != 0 && !folders.PackPositions) 1069 { 1070 // if there are folders, we need PackPositions also 1071 folders.PackPositions.Alloc(1); 1072 folders.PackPositions[0] = 0; 1073 } 1074 1075 if (type == NID::kSubStreamsInfo) 1076 { 1077 ReadSubStreamsInfo(folders, unpackSizes, digests); 1078 type = ReadID(); 1079 } 1080 else 1081 { 1082 folders.NumUnpackStreamsVector.Alloc(folders.NumFolders); 1083 /* If digests.Defs.Size() == 0, it means that there are no crcs. 1084 So we don't need to fill digests with values. */ 1085 // digests.Vals.ClearAndSetSize(folders.NumFolders); 1086 // BoolVector_Fill_False(digests.Defs, folders.NumFolders); 1087 for (CNum i = 0; i < folders.NumFolders; i++) 1088 { 1089 folders.NumUnpackStreamsVector[i] = 1; 1090 unpackSizes.Add(folders.GetFolderUnpackSize(i)); 1091 // digests.Vals[i] = 0; 1092 } 1093 } 1094 1095 if (type != NID::kEnd) 1096 ThrowIncorrect(); 1097} 1098 1099void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v) 1100{ 1101 v.ClearAndSetSize(numItems); 1102 Byte b = 0; 1103 Byte mask = 0; 1104 bool *p = &v[0]; 1105 for (unsigned i = 0; i < numItems; i++) 1106 { 1107 if (mask == 0) 1108 { 1109 b = ReadByte(); 1110 mask = 0x80; 1111 } 1112 p[i] = ((b & mask) != 0); 1113 mask = (Byte)(mask >> 1); 1114 } 1115} 1116 1117void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v) 1118{ 1119 const Byte allAreDefined = ReadByte(); 1120 if (allAreDefined == 0) 1121 { 1122 ReadBoolVector(numItems, v); 1123 return; 1124 } 1125 v.ClearAndSetSize(numItems); 1126 bool *p = &v[0]; 1127 for (unsigned i = 0; i < numItems; i++) 1128 p[i] = true; 1129} 1130 1131void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector, 1132 CUInt64DefVector &v, unsigned numItems) 1133{ 1134 ReadBoolVector2(numItems, v.Defs); 1135 1136 CStreamSwitch streamSwitch; 1137 streamSwitch.Set(this, &dataVector); 1138 1139 v.Vals.ClearAndSetSize(numItems); 1140 UInt64 *p = &v.Vals[0]; 1141 const bool *defs = &v.Defs[0]; 1142 1143 for (unsigned i = 0; i < numItems; i++) 1144 { 1145 UInt64 t = 0; 1146 if (defs[i]) 1147 t = ReadUInt64(); 1148 p[i] = t; 1149 } 1150} 1151 1152HRESULT CInArchive::ReadAndDecodePackedStreams( 1153 DECL_EXTERNAL_CODECS_LOC_VARS 1154 UInt64 baseOffset, 1155 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector 1156 Z7_7Z_DECODER_CRYPRO_VARS_DECL 1157 ) 1158{ 1159 CFolders folders; 1160 CRecordVector<UInt64> unpackSizes; 1161 CUInt32DefVector digests; 1162 1163 ReadStreamsInfo(NULL, 1164 dataOffset, 1165 folders, 1166 unpackSizes, 1167 digests); 1168 1169 CDecoder decoder(_useMixerMT); 1170 1171 for (CNum i = 0; i < folders.NumFolders; i++) 1172 { 1173 CByteBuffer &data = dataVector.AddNew(); 1174 const UInt64 unpackSize64 = folders.GetFolderUnpackSize(i); 1175 const size_t unpackSize = (size_t)unpackSize64; 1176 if (unpackSize != unpackSize64) 1177 ThrowUnsupported(); 1178 data.Alloc(unpackSize); 1179 1180 CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream; 1181 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; 1182 outStreamSpec->Init(data, unpackSize); 1183 1184 bool dataAfterEnd_Error = false; 1185 1186 HRESULT result = decoder.Decode( 1187 EXTERNAL_CODECS_LOC_VARS 1188 _stream, baseOffset + dataOffset, 1189 folders, i, 1190 NULL, // &unpackSize64 1191 1192 outStream, 1193 NULL, // *compressProgress 1194 1195 NULL // **inStreamMainRes 1196 , dataAfterEnd_Error 1197 1198 Z7_7Z_DECODER_CRYPRO_VARS 1199 #if !defined(Z7_ST) 1200 , false // mtMode 1201 , 1 // numThreads 1202 , 0 // memUsage 1203 #endif 1204 ); 1205 1206 RINOK(result) 1207 1208 if (dataAfterEnd_Error) 1209 ThereIsHeaderError = true; 1210 1211 if (unpackSize != outStreamSpec->GetPos()) 1212 ThrowIncorrect(); 1213 1214 if (folders.FolderCRCs.ValidAndDefined(i)) 1215 if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i]) 1216 ThrowIncorrect(); 1217 } 1218 1219 if (folders.PackPositions) 1220 HeadersSize += folders.PackPositions[folders.NumPackStreams]; 1221 1222 return S_OK; 1223} 1224 1225HRESULT CInArchive::ReadHeader( 1226 DECL_EXTERNAL_CODECS_LOC_VARS 1227 CDbEx &db 1228 Z7_7Z_DECODER_CRYPRO_VARS_DECL 1229 ) 1230{ 1231 UInt64 type = ReadID(); 1232 1233 if (type == NID::kArchiveProperties) 1234 { 1235 ReadArchiveProperties(db.ArcInfo); 1236 type = ReadID(); 1237 } 1238 1239 CObjectVector<CByteBuffer> dataVector; 1240 1241 if (type == NID::kAdditionalStreamsInfo) 1242 { 1243 const HRESULT result = ReadAndDecodePackedStreams( 1244 EXTERNAL_CODECS_LOC_VARS 1245 db.ArcInfo.StartPositionAfterHeader, 1246 db.ArcInfo.DataStartPosition2, 1247 dataVector 1248 Z7_7Z_DECODER_CRYPRO_VARS 1249 ); 1250 RINOK(result) 1251 db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader; 1252 type = ReadID(); 1253 } 1254 1255 CRecordVector<UInt64> unpackSizes; 1256 CUInt32DefVector digests; 1257 1258 if (type == NID::kMainStreamsInfo) 1259 { 1260 ReadStreamsInfo(&dataVector, 1261 db.ArcInfo.DataStartPosition, 1262 (CFolders &)db, 1263 unpackSizes, 1264 digests); 1265 db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader; 1266 type = ReadID(); 1267 } 1268 1269 if (type == NID::kFilesInfo) 1270 { 1271 1272 const CNum numFiles = ReadNum(); 1273 1274 db.ArcInfo.FileInfoPopIDs.Add(NID::kSize); 1275 // if (!db.PackSizes.IsEmpty()) 1276 db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo); 1277 if (numFiles > 0 && !digests.Defs.IsEmpty()) 1278 db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC); 1279 1280 CBoolVector emptyStreamVector; 1281 CBoolVector emptyFileVector; 1282 CBoolVector antiFileVector; 1283 CNum numEmptyStreams = 0; 1284 1285 for (;;) 1286 { 1287 const UInt64 type2 = ReadID(); 1288 if (type2 == NID::kEnd) 1289 break; 1290 const UInt64 size = ReadNumber(); 1291 if (size > _inByteBack->GetRem()) 1292 ThrowIncorrect(); 1293 CStreamSwitch switchProp; 1294 switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true); 1295 bool addPropIdToList = true; 1296 bool isKnownType = true; 1297 if (type2 > ((UInt32)1 << 30)) 1298 isKnownType = false; 1299 else switch ((UInt32)type2) 1300 { 1301 case NID::kName: 1302 { 1303 CStreamSwitch streamSwitch; 1304 streamSwitch.Set(this, &dataVector); 1305 const size_t rem = _inByteBack->GetRem(); 1306 db.NamesBuf.Alloc(rem); 1307 ReadBytes(db.NamesBuf, rem); 1308 db.NameOffsets.Alloc(numFiles + 1); 1309 size_t pos = 0; 1310 unsigned i; 1311 for (i = 0; i < numFiles; i++) 1312 { 1313 const size_t curRem = (rem - pos) / 2; 1314 const UInt16 *buf = (const UInt16 *)(const void *)(db.NamesBuf + pos); 1315 size_t j; 1316 for (j = 0; j < curRem && buf[j] != 0; j++); 1317 if (j == curRem) 1318 ThrowEndOfData(); 1319 db.NameOffsets[i] = pos / 2; 1320 pos += j * 2 + 2; 1321 } 1322 db.NameOffsets[i] = pos / 2; 1323 if (pos != rem) 1324 ThereIsHeaderError = true; 1325 break; 1326 } 1327 1328 case NID::kWinAttrib: 1329 { 1330 ReadBoolVector2(numFiles, db.Attrib.Defs); 1331 CStreamSwitch streamSwitch; 1332 streamSwitch.Set(this, &dataVector); 1333 Read_UInt32_Vector(db.Attrib); 1334 break; 1335 } 1336 1337 /* 1338 case NID::kIsAux: 1339 { 1340 ReadBoolVector(numFiles, db.IsAux); 1341 break; 1342 } 1343 case NID::kParent: 1344 { 1345 db.IsTree = true; 1346 // CBoolVector boolVector; 1347 // ReadBoolVector2(numFiles, boolVector); 1348 // CStreamSwitch streamSwitch; 1349 // streamSwitch.Set(this, &dataVector); 1350 CBoolVector boolVector; 1351 ReadBoolVector2(numFiles, boolVector); 1352 1353 db.ThereAreAltStreams = false; 1354 for (i = 0; i < numFiles; i++) 1355 { 1356 CFileItem &file = db.Files[i]; 1357 // file.Parent = -1; 1358 // if (boolVector[i]) 1359 file.Parent = (int)ReadUInt32(); 1360 file.IsAltStream = !boolVector[i]; 1361 if (file.IsAltStream) 1362 db.ThereAreAltStreams = true; 1363 } 1364 break; 1365 } 1366 */ 1367 case NID::kEmptyStream: 1368 { 1369 ReadBoolVector(numFiles, emptyStreamVector); 1370 numEmptyStreams = BoolVector_CountSum(emptyStreamVector); 1371 emptyFileVector.Clear(); 1372 antiFileVector.Clear(); 1373 break; 1374 } 1375 case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break; 1376 case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break; 1377 case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (unsigned)numFiles); break; 1378 case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (unsigned)numFiles); break; 1379 case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (unsigned)numFiles); break; 1380 case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (unsigned)numFiles); break; 1381 case NID::kDummy: 1382 { 1383 for (UInt64 j = 0; j < size; j++) 1384 if (ReadByte() != 0) 1385 ThereIsHeaderError = true; 1386 addPropIdToList = false; 1387 break; 1388 } 1389 /* 1390 case NID::kNtSecure: 1391 { 1392 try 1393 { 1394 { 1395 CStreamSwitch streamSwitch; 1396 streamSwitch.Set(this, &dataVector); 1397 UInt32 numDescriptors = ReadUInt32(); 1398 size_t offset = 0; 1399 db.SecureOffsets.Clear(); 1400 for (i = 0; i < numDescriptors; i++) 1401 { 1402 UInt32 size = ReadUInt32(); 1403 db.SecureOffsets.Add(offset); 1404 offset += size; 1405 } 1406 // ThrowIncorrect();; 1407 db.SecureOffsets.Add(offset); 1408 db.SecureBuf.SetCapacity(offset); 1409 for (i = 0; i < numDescriptors; i++) 1410 { 1411 offset = db.SecureOffsets[i]; 1412 ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset); 1413 } 1414 db.SecureIDs.Clear(); 1415 for (unsigned i = 0; i < numFiles; i++) 1416 { 1417 db.SecureIDs.Add(ReadNum()); 1418 // db.SecureIDs.Add(ReadUInt32()); 1419 } 1420 // ReadUInt32(); 1421 if (_inByteBack->GetRem() != 0) 1422 ThrowIncorrect();; 1423 } 1424 } 1425 catch(CInArchiveException &) 1426 { 1427 ThereIsHeaderError = true; 1428 addPropIdToList = isKnownType = false; 1429 db.ClearSecure(); 1430 } 1431 break; 1432 } 1433 */ 1434 default: 1435 addPropIdToList = isKnownType = false; 1436 } 1437 if (isKnownType) 1438 { 1439 if (addPropIdToList) 1440 db.ArcInfo.FileInfoPopIDs.Add(type2); 1441 } 1442 else 1443 { 1444 db.UnsupportedFeatureWarning = true; 1445 _inByteBack->SkipRem(); 1446 } 1447 // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 0.02) 1448 if (_inByteBack->GetRem() != 0) 1449 ThrowIncorrect(); 1450 } 1451 1452 type = ReadID(); // Read (NID::kEnd) end of headers 1453 1454 if (numFiles - numEmptyStreams != unpackSizes.Size()) 1455 ThrowUnsupported(); 1456 1457 CNum emptyFileIndex = 0; 1458 CNum sizeIndex = 0; 1459 1460 const CNum numAntiItems = BoolVector_CountSum(antiFileVector); 1461 1462 if (numAntiItems != 0) 1463 db.IsAnti.ClearAndSetSize(numFiles); 1464 1465 db.Files.ClearAndSetSize(numFiles); 1466 1467 for (CNum i = 0; i < numFiles; i++) 1468 { 1469 CFileItem &file = db.Files[i]; 1470 bool isAnti; 1471 file.Crc = 0; 1472 if (!BoolVector_Item_IsValidAndTrue(emptyStreamVector, i)) 1473 { 1474 file.HasStream = true; 1475 file.IsDir = false; 1476 isAnti = false; 1477 file.Size = unpackSizes[sizeIndex]; 1478 file.CrcDefined = digests.ValidAndDefined(sizeIndex); 1479 if (file.CrcDefined) 1480 file.Crc = digests.Vals[sizeIndex]; 1481 sizeIndex++; 1482 } 1483 else 1484 { 1485 file.HasStream = false; 1486 file.IsDir = !BoolVector_Item_IsValidAndTrue(emptyFileVector, emptyFileIndex); 1487 isAnti = BoolVector_Item_IsValidAndTrue(antiFileVector, emptyFileIndex); 1488 emptyFileIndex++; 1489 file.Size = 0; 1490 file.CrcDefined = false; 1491 } 1492 if (numAntiItems != 0) 1493 db.IsAnti[i] = isAnti; 1494 } 1495 1496 } 1497 1498 db.FillLinks(); 1499 1500 if (type != NID::kEnd || _inByteBack->GetRem() != 0) 1501 { 1502 db.UnsupportedFeatureWarning = true; 1503 // ThrowIncorrect(); 1504 } 1505 1506 return S_OK; 1507} 1508 1509 1510void CDbEx::FillLinks() 1511{ 1512 FolderStartFileIndex.Alloc(NumFolders); 1513 FileIndexToFolderIndexMap.Alloc(Files.Size()); 1514 1515 CNum folderIndex = 0; 1516 CNum indexInFolder = 0; 1517 unsigned i; 1518 1519 for (i = 0; i < Files.Size(); i++) 1520 { 1521 const bool emptyStream = !Files[i].HasStream; 1522 if (indexInFolder == 0) 1523 { 1524 if (emptyStream) 1525 { 1526 FileIndexToFolderIndexMap[i] = kNumNoIndex; 1527 continue; 1528 } 1529 // v3.13 incorrectly worked with empty folders 1530 // v4.07: we skip empty folders 1531 for (;;) 1532 { 1533 if (folderIndex >= NumFolders) 1534 ThrowIncorrect(); 1535 FolderStartFileIndex[folderIndex] = i; 1536 if (NumUnpackStreamsVector[folderIndex] != 0) 1537 break; 1538 folderIndex++; 1539 } 1540 } 1541 FileIndexToFolderIndexMap[i] = folderIndex; 1542 if (emptyStream) 1543 continue; 1544 if (++indexInFolder >= NumUnpackStreamsVector[folderIndex]) 1545 { 1546 folderIndex++; 1547 indexInFolder = 0; 1548 } 1549 } 1550 1551 if (indexInFolder != 0) 1552 { 1553 folderIndex++; 1554 // 18.06 1555 ThereIsHeaderError = true; 1556 // ThrowIncorrect(); 1557 } 1558 1559 for (;;) 1560 { 1561 if (folderIndex >= NumFolders) 1562 return; 1563 FolderStartFileIndex[folderIndex] = i; 1564 if (NumUnpackStreamsVector[folderIndex] != 0) 1565 { 1566 // 18.06 1567 ThereIsHeaderError = true; 1568 // ThrowIncorrect(); 1569 } 1570 folderIndex++; 1571 } 1572} 1573 1574 1575HRESULT CInArchive::ReadDatabase2( 1576 DECL_EXTERNAL_CODECS_LOC_VARS 1577 CDbEx &db 1578 Z7_7Z_DECODER_CRYPRO_VARS_DECL 1579 ) 1580{ 1581 db.Clear(); 1582 db.ArcInfo.StartPosition = _arhiveBeginStreamPosition; 1583 1584 db.ArcInfo.Version.Major = _header[6]; 1585 db.ArcInfo.Version.Minor = _header[7]; 1586 1587 if (db.ArcInfo.Version.Major != kMajorVersion) 1588 { 1589 // db.UnsupportedVersion = true; 1590 return S_FALSE; 1591 } 1592 1593 UInt64 nextHeaderOffset = Get64(_header + 12); 1594 UInt64 nextHeaderSize = Get64(_header + 20); 1595 UInt32 nextHeaderCRC = Get32(_header + 28); 1596 1597 #ifdef FORMAT_7Z_RECOVERY 1598 const UInt32 crcFromArc = Get32(_header + 8); 1599 if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0) 1600 { 1601 UInt64 cur, fileSize; 1602 RINOK(InStream_GetPos(_stream, cur)) 1603 const unsigned kCheckSize = 512; 1604 Byte buf[kCheckSize]; 1605 RINOK(InStream_GetSize_SeekToEnd(_stream, fileSize)) 1606 const UInt64 rem = fileSize - cur; 1607 unsigned checkSize = kCheckSize; 1608 if (rem < kCheckSize) 1609 checkSize = (unsigned)(rem); 1610 if (checkSize < 3) 1611 return S_FALSE; 1612 RINOK(InStream_SeekSet(_stream, fileSize - checkSize)) 1613 RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize)) 1614 1615 if (buf[checkSize - 1] != 0) 1616 return S_FALSE; 1617 1618 unsigned i; 1619 for (i = checkSize - 2;; i--) 1620 { 1621 if ((buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo) || 1622 (buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo)) 1623 break; 1624 if (i == 0) 1625 return S_FALSE; 1626 } 1627 nextHeaderSize = checkSize - i; 1628 nextHeaderOffset = rem - nextHeaderSize; 1629 nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize); 1630 RINOK(InStream_SeekSet(_stream, cur)) 1631 db.StartHeaderWasRecovered = true; 1632 } 1633 else 1634 #endif 1635 { 1636 // Crc was tested already at signature check 1637 // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect(); 1638 } 1639 1640 db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize; 1641 db.PhySize = kHeaderSize; 1642 1643 db.IsArc = false; 1644 if ((Int64)nextHeaderOffset < 0 || 1645 nextHeaderSize > ((UInt64)1 << 62)) 1646 return S_FALSE; 1647 1648 HeadersSize = kHeaderSize; 1649 1650 if (nextHeaderSize == 0) 1651 { 1652 if (nextHeaderOffset != 0) 1653 return S_FALSE; 1654 db.IsArc = true; 1655 db.HeadersSize = HeadersSize; 1656 return S_OK; 1657 } 1658 1659 if (!db.StartHeaderWasRecovered) 1660 db.IsArc = true; 1661 1662 HeadersSize += nextHeaderSize; 1663 // db.EndHeaderOffset = nextHeaderOffset; 1664 _rangeLimit = nextHeaderOffset; 1665 1666 db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize; 1667 if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize) 1668 { 1669 db.UnexpectedEnd = true; 1670 return S_FALSE; 1671 } 1672 RINOK(_stream->Seek((Int64)nextHeaderOffset, STREAM_SEEK_CUR, NULL)) 1673 1674 const size_t nextHeaderSize_t = (size_t)nextHeaderSize; 1675 if (nextHeaderSize_t != nextHeaderSize) 1676 return E_OUTOFMEMORY; 1677 CByteBuffer buffer2(nextHeaderSize_t); 1678 1679 RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t)) 1680 1681 if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC) 1682 ThrowIncorrect(); 1683 1684 if (!db.StartHeaderWasRecovered) 1685 db.PhySizeWasConfirmed = true; 1686 1687 CStreamSwitch streamSwitch; 1688 streamSwitch.Set(this, buffer2); 1689 1690 CObjectVector<CByteBuffer> dataVector; 1691 1692 const UInt64 type = ReadID(); 1693 if (type != NID::kHeader) 1694 { 1695 if (type != NID::kEncodedHeader) 1696 ThrowIncorrect(); 1697 const HRESULT result = ReadAndDecodePackedStreams( 1698 EXTERNAL_CODECS_LOC_VARS 1699 db.ArcInfo.StartPositionAfterHeader, 1700 db.ArcInfo.DataStartPosition2, 1701 dataVector 1702 Z7_7Z_DECODER_CRYPRO_VARS 1703 ); 1704 RINOK(result) 1705 if (dataVector.Size() == 0) 1706 return S_OK; 1707 if (dataVector.Size() > 1) 1708 ThrowIncorrect(); 1709 streamSwitch.Remove(); 1710 streamSwitch.Set(this, dataVector.Front()); 1711 if (ReadID() != NID::kHeader) 1712 ThrowIncorrect(); 1713 } 1714 1715 db.IsArc = true; 1716 1717 db.HeadersSize = HeadersSize; 1718 1719 return ReadHeader( 1720 EXTERNAL_CODECS_LOC_VARS 1721 db 1722 Z7_7Z_DECODER_CRYPRO_VARS 1723 ); 1724} 1725 1726 1727HRESULT CInArchive::ReadDatabase( 1728 DECL_EXTERNAL_CODECS_LOC_VARS 1729 CDbEx &db 1730 Z7_7Z_DECODER_CRYPRO_VARS_DECL 1731 ) 1732{ 1733 try 1734 { 1735 const HRESULT res = ReadDatabase2( 1736 EXTERNAL_CODECS_LOC_VARS db 1737 Z7_7Z_DECODER_CRYPRO_VARS 1738 ); 1739 if (ThereIsHeaderError) 1740 db.ThereIsHeaderError = true; 1741 if (res == E_NOTIMPL) 1742 ThrowUnsupported(); 1743 return res; 1744 } 1745 catch(CUnsupportedFeatureException &) 1746 { 1747 db.UnsupportedFeatureError = true; 1748 return S_FALSE; 1749 } 1750 catch(CInArchiveException &) 1751 { 1752 db.ThereIsHeaderError = true; 1753 return S_FALSE; 1754 } 1755} 1756 1757}} 1758