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