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