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