tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

7zIn.cpp (42341B)


      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    folderIndex++;
   1469  /*
   1470  if (indexInFolder != 0)
   1471    ThrowIncorrect();
   1472  */
   1473  
   1474  for (;;)
   1475  {
   1476    if (folderIndex >= NumFolders)
   1477      return;
   1478    FolderStartFileIndex[folderIndex] = i;
   1479    /*
   1480    if (NumUnpackStreamsVector[folderIndex] != 0)
   1481      ThrowIncorrect();;
   1482    */
   1483    folderIndex++;
   1484  }
   1485 }
   1486 
   1487 
   1488 HRESULT CInArchive::ReadDatabase2(
   1489    DECL_EXTERNAL_CODECS_LOC_VARS
   1490    CDbEx &db
   1491    _7Z_DECODER_CRYPRO_VARS_DECL
   1492    )
   1493 {
   1494  db.Clear();
   1495  db.ArcInfo.StartPosition = _arhiveBeginStreamPosition;
   1496 
   1497  db.ArcInfo.Version.Major = _header[6];
   1498  db.ArcInfo.Version.Minor = _header[7];
   1499 
   1500  if (db.ArcInfo.Version.Major != kMajorVersion)
   1501  {
   1502    // db.UnsupportedVersion = true;
   1503    return S_FALSE;
   1504  }
   1505 
   1506  UInt64 nextHeaderOffset = Get64(_header + 12);
   1507  UInt64 nextHeaderSize = Get64(_header + 20);
   1508  UInt32 nextHeaderCRC = Get32(_header + 28);
   1509 
   1510  #ifdef FORMAT_7Z_RECOVERY
   1511  UInt32 crcFromArc = Get32(_header + 8);
   1512  if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
   1513  {
   1514    UInt64 cur, fileSize;
   1515    RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
   1516    const unsigned kCheckSize = 512;
   1517    Byte buf[kCheckSize];
   1518    RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize));
   1519    UInt64 rem = fileSize - cur;
   1520    unsigned checkSize = kCheckSize;
   1521    if (rem < kCheckSize)
   1522      checkSize = (unsigned)(rem);
   1523    if (checkSize < 3)
   1524      return S_FALSE;
   1525    RINOK(_stream->Seek(fileSize - checkSize, STREAM_SEEK_SET, NULL));
   1526    RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));
   1527 
   1528    if (buf[checkSize - 1] != 0)
   1529      return S_FALSE;
   1530 
   1531    unsigned i;
   1532    for (i = checkSize - 2;; i--)
   1533    {
   1534      if (buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo ||
   1535          buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo)
   1536        break;
   1537      if (i == 0)
   1538        return S_FALSE;
   1539    }
   1540    nextHeaderSize = checkSize - i;
   1541    nextHeaderOffset = rem - nextHeaderSize;
   1542    nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
   1543    RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
   1544    db.StartHeaderWasRecovered = true;
   1545  }
   1546  else
   1547  #endif
   1548  {
   1549    // Crc was tested already at signature check
   1550    // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect();
   1551  }
   1552 
   1553  db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
   1554  db.PhySize = kHeaderSize;
   1555 
   1556  db.IsArc = false;
   1557  if ((Int64)nextHeaderOffset < 0 ||
   1558      nextHeaderSize > ((UInt64)1 << 62))
   1559    return S_FALSE;
   1560  if (nextHeaderSize == 0)
   1561  {
   1562    if (nextHeaderOffset != 0)
   1563      return S_FALSE;
   1564    db.IsArc = true;
   1565    return S_OK;
   1566  }
   1567  
   1568  if (!db.StartHeaderWasRecovered)
   1569    db.IsArc = true;
   1570  
   1571  HeadersSize += kHeaderSize + nextHeaderSize;
   1572  db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
   1573  if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize)
   1574  {
   1575    db.UnexpectedEnd = true;
   1576    return S_FALSE;
   1577  }
   1578  RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
   1579 
   1580  size_t nextHeaderSize_t = (size_t)nextHeaderSize;
   1581  if (nextHeaderSize_t != nextHeaderSize)
   1582    return E_OUTOFMEMORY;
   1583  CByteBuffer buffer2(nextHeaderSize_t);
   1584 
   1585  RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t));
   1586 
   1587  if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC)
   1588    ThrowIncorrect();
   1589 
   1590  if (!db.StartHeaderWasRecovered)
   1591    db.PhySizeWasConfirmed = true;
   1592  
   1593  CStreamSwitch streamSwitch;
   1594  streamSwitch.Set(this, buffer2);
   1595  
   1596  CObjectVector<CByteBuffer> dataVector;
   1597  
   1598  UInt64 type = ReadID();
   1599  if (type != NID::kHeader)
   1600  {
   1601    if (type != NID::kEncodedHeader)
   1602      ThrowIncorrect();
   1603    HRESULT result = ReadAndDecodePackedStreams(
   1604        EXTERNAL_CODECS_LOC_VARS
   1605        db.ArcInfo.StartPositionAfterHeader,
   1606        db.ArcInfo.DataStartPosition2,
   1607        dataVector
   1608        _7Z_DECODER_CRYPRO_VARS
   1609        );
   1610    RINOK(result);
   1611    if (dataVector.Size() == 0)
   1612      return S_OK;
   1613    if (dataVector.Size() > 1)
   1614      ThrowIncorrect();
   1615    streamSwitch.Remove();
   1616    streamSwitch.Set(this, dataVector.Front());
   1617    if (ReadID() != NID::kHeader)
   1618      ThrowIncorrect();
   1619  }
   1620 
   1621  db.IsArc = true;
   1622 
   1623  db.HeadersSize = HeadersSize;
   1624 
   1625  return ReadHeader(
   1626    EXTERNAL_CODECS_LOC_VARS
   1627    db
   1628    _7Z_DECODER_CRYPRO_VARS
   1629    );
   1630 }
   1631 
   1632 
   1633 HRESULT CInArchive::ReadDatabase(
   1634    DECL_EXTERNAL_CODECS_LOC_VARS
   1635    CDbEx &db
   1636    _7Z_DECODER_CRYPRO_VARS_DECL
   1637    )
   1638 {
   1639  try
   1640  {
   1641    HRESULT res = ReadDatabase2(
   1642      EXTERNAL_CODECS_LOC_VARS db
   1643      _7Z_DECODER_CRYPRO_VARS
   1644      );
   1645    if (ThereIsHeaderError)
   1646      db.ThereIsHeaderError = true;
   1647    if (res == E_NOTIMPL)
   1648      ThrowUnsupported();
   1649    return res;
   1650  }
   1651  catch(CUnsupportedFeatureException &)
   1652  {
   1653    db.UnsupportedFeatureError = true;
   1654    return S_FALSE;
   1655  }
   1656  catch(CInArchiveException &)
   1657  {
   1658    db.ThereIsHeaderError = true;
   1659    return S_FALSE;
   1660  }
   1661 }
   1662 
   1663 }}