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