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