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