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