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