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