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