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