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