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