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