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