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