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