5 #include "../../../../C/7zCrc.h"
\r
6 #include "../../../../C/CpuArch.h"
\r
8 #include "../../Common/StreamObjects.h"
\r
9 #include "../../Common/StreamUtils.h"
\r
11 #include "7zDecode.h"
\r
14 #define Get16(p) GetUi16(p)
\r
15 #define Get32(p) GetUi32(p)
\r
16 #define Get64(p) GetUi64(p)
\r
18 // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader
\r
20 #define FORMAT_7Z_RECOVERY
\r
23 namespace NArchive {
\r
26 static void BoolVector_Fill_False(CBoolVector &v, int size)
\r
30 for (int i = 0; i < size; i++)
\r
34 static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index)
\r
36 if (index >= (UInt32)v.Size())
\r
38 bool res = v[index];
\r
43 bool CFolder::CheckStructure() const
\r
45 const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it
\r
46 const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax
\r
47 const int kNumBindsMax = 32;
\r
49 if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax)
\r
54 BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size());
\r
57 for (i = 0; i < BindPairs.Size(); i++)
\r
58 if (BoolVector_GetAndSet(v, BindPairs[i].InIndex))
\r
60 for (i = 0; i < PackStreams.Size(); i++)
\r
61 if (BoolVector_GetAndSet(v, PackStreams[i]))
\r
64 BoolVector_Fill_False(v, UnpackSizes.Size());
\r
65 for (i = 0; i < BindPairs.Size(); i++)
\r
66 if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex))
\r
70 UInt32 mask[kMaskSize];
\r
72 for (i = 0; i < kMaskSize; i++)
\r
76 CIntVector inStreamToCoder, outStreamToCoder;
\r
77 for (i = 0; i < Coders.Size(); i++)
\r
80 const CCoderInfo &coder = Coders[i];
\r
81 for (j = 0; j < coder.NumInStreams; j++)
\r
82 inStreamToCoder.Add(i);
\r
83 for (j = 0; j < coder.NumOutStreams; j++)
\r
84 outStreamToCoder.Add(i);
\r
87 for (i = 0; i < BindPairs.Size(); i++)
\r
89 const CBindPair &bp = BindPairs[i];
\r
90 mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]);
\r
94 for (i = 0; i < kMaskSize; i++)
\r
95 for (int j = 0; j < kMaskSize; j++)
\r
96 if (((1 << j) & mask[i]) != 0)
\r
99 for (i = 0; i < kMaskSize; i++)
\r
100 if (((1 << i) & mask[i]) != 0)
\r
106 class CInArchiveException {};
\r
108 static void ThrowException() { throw CInArchiveException(); }
\r
109 static inline void ThrowEndOfData() { ThrowException(); }
\r
110 static inline void ThrowUnsupported() { ThrowException(); }
\r
111 static inline void ThrowIncorrect() { ThrowException(); }
\r
112 static inline void ThrowUnsupportedVersion() { ThrowException(); }
\r
115 class CInArchiveException
\r
120 kUnsupportedVersion = 0,
\r
125 CInArchiveException(CCauseType cause): Cause(cause) {};
\r
128 static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
\r
129 static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); }
\r
130 static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
\r
131 static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); }
\r
132 static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
\r
135 class CStreamSwitch
\r
137 CInArchive *_archive;
\r
140 CStreamSwitch(): _needRemove(false) {}
\r
141 ~CStreamSwitch() { Remove(); }
\r
143 void Set(CInArchive *archive, const Byte *data, size_t size);
\r
144 void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
\r
145 void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
\r
148 void CStreamSwitch::Remove()
\r
152 _archive->DeleteByteStream();
\r
153 _needRemove = false;
\r
157 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
\r
160 _archive = archive;
\r
161 _archive->AddByteStream(data, size);
\r
162 _needRemove = true;
\r
165 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
\r
167 Set(archive, byteBuffer, byteBuffer.GetCapacity());
\r
170 void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
\r
173 Byte external = archive->ReadByte();
\r
176 int dataIndex = (int)archive->ReadNum();
\r
177 if (dataIndex < 0 || dataIndex >= dataVector->Size())
\r
179 Set(archive, (*dataVector)[dataIndex]);
\r
183 Byte CInByte2::ReadByte()
\r
187 return _buffer[_pos++];
\r
190 void CInByte2::ReadBytes(Byte *data, size_t size)
\r
192 if (size > _size - _pos)
\r
194 for (size_t i = 0; i < size; i++)
\r
195 data[i] = _buffer[_pos++];
\r
198 void CInByte2::SkipData(UInt64 size)
\r
200 if (size > _size - _pos)
\r
202 _pos += (size_t)size;
\r
205 void CInByte2::SkipData()
\r
207 SkipData(ReadNumber());
\r
210 UInt64 CInByte2::ReadNumber()
\r
214 Byte firstByte = _buffer[_pos++];
\r
217 for (int i = 0; i < 8; i++)
\r
219 if ((firstByte & mask) == 0)
\r
221 UInt64 highPart = firstByte & (mask - 1);
\r
222 value += (highPart << (i * 8));
\r
227 value |= ((UInt64)_buffer[_pos++] << (8 * i));
\r
233 CNum CInByte2::ReadNum()
\r
235 UInt64 value = ReadNumber();
\r
236 if (value > kNumMax)
\r
237 ThrowUnsupported();
\r
238 return (CNum)value;
\r
241 UInt32 CInByte2::ReadUInt32()
\r
243 if (_pos + 4 > _size)
\r
245 UInt32 res = Get32(_buffer + _pos);
\r
250 UInt64 CInByte2::ReadUInt64()
\r
252 if (_pos + 8 > _size)
\r
254 UInt64 res = Get64(_buffer + _pos);
\r
259 void CInByte2::ReadString(UString &s)
\r
261 const Byte *buf = _buffer + _pos;
\r
262 size_t rem = (_size - _pos) / 2 * 2;
\r
265 for (i = 0; i < rem; i += 2)
\r
266 if (buf[i] == 0 && buf[i + 1] == 0)
\r
272 int len = (int)(rem / 2);
\r
273 if (len < 0 || (size_t)len * 2 != rem)
\r
274 ThrowUnsupported();
\r
275 wchar_t *p = s.GetBuffer(len);
\r
277 for (i = 0; i < len; i++, buf += 2)
\r
278 p[i] = (wchar_t)Get16(buf);
\r
279 s.ReleaseBuffer(len);
\r
283 static inline bool TestSignature(const Byte *p)
\r
285 for (int i = 0; i < kSignatureSize; i++)
\r
286 if (p[i] != kSignature[i])
\r
288 return CrcCalc(p + 12, 20) == GetUi32(p + 8);
\r
291 #ifdef FORMAT_7Z_RECOVERY
\r
292 static inline bool TestSignature2(const Byte *p)
\r
295 for (i = 0; i < kSignatureSize; i++)
\r
296 if (p[i] != kSignature[i])
\r
298 if (CrcCalc(p + 12, 20) == GetUi32(p + 8))
\r
300 for (i = 8; i < kHeaderSize; i++)
\r
303 return (p[6] != 0 || p[7] != 0);
\r
306 #define TestSignature2(p) TestSignature(p)
\r
309 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
\r
311 RINOK(ReadStream_FALSE(stream, _header, kHeaderSize));
\r
313 if (TestSignature2(_header))
\r
316 CByteBuffer byteBuffer;
\r
317 const UInt32 kBufferSize = (1 << 16);
\r
318 byteBuffer.SetCapacity(kBufferSize);
\r
319 Byte *buffer = byteBuffer;
\r
320 UInt32 numPrevBytes = kHeaderSize;
\r
321 memcpy(buffer, _header, kHeaderSize);
\r
322 UInt64 curTestPos = _arhiveBeginStreamPosition;
\r
325 if (searchHeaderSizeLimit != NULL)
\r
326 if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
\r
330 UInt32 numReadBytes = kBufferSize - numPrevBytes;
\r
331 UInt32 processedSize;
\r
332 RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
\r
333 numPrevBytes += processedSize;
\r
334 if (processedSize == 0)
\r
337 while (numPrevBytes <= kHeaderSize);
\r
338 UInt32 numTests = numPrevBytes - kHeaderSize;
\r
339 for (UInt32 pos = 0; pos < numTests; pos++)
\r
341 for (; buffer[pos] != '7' && pos < numTests; pos++);
\r
342 if (pos == numTests)
\r
344 if (TestSignature(buffer + pos))
\r
346 memcpy(_header, buffer + pos, kHeaderSize);
\r
348 _arhiveBeginStreamPosition = curTestPos;
\r
349 return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
\r
352 curTestPos += numTests;
\r
353 numPrevBytes -= numTests;
\r
354 memmove(buffer, buffer + numTests, numPrevBytes);
\r
359 // S_FALSE means that file is not archive
\r
360 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
\r
364 RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
\r
365 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
\r
370 void CInArchive::Close()
\r
375 void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
\r
379 if (ReadID() == NID::kEnd)
\r
385 void CInArchive::GetNextFolderItem(CFolder &folder)
\r
387 CNum numCoders = ReadNum();
\r
389 folder.Coders.Clear();
\r
390 folder.Coders.Reserve((int)numCoders);
\r
391 CNum numInStreams = 0;
\r
392 CNum numOutStreams = 0;
\r
394 for (i = 0; i < numCoders; i++)
\r
396 folder.Coders.Add(CCoderInfo());
\r
397 CCoderInfo &coder = folder.Coders.Back();
\r
400 Byte mainByte = ReadByte();
\r
401 int idSize = (mainByte & 0xF);
\r
403 ReadBytes(longID, idSize);
\r
405 ThrowUnsupported();
\r
407 for (int j = 0; j < idSize; j++)
\r
408 id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
\r
409 coder.MethodID = id;
\r
411 if ((mainByte & 0x10) != 0)
\r
413 coder.NumInStreams = ReadNum();
\r
414 coder.NumOutStreams = ReadNum();
\r
418 coder.NumInStreams = 1;
\r
419 coder.NumOutStreams = 1;
\r
421 if ((mainByte & 0x20) != 0)
\r
423 CNum propsSize = ReadNum();
\r
424 coder.Props.SetCapacity((size_t)propsSize);
\r
425 ReadBytes((Byte *)coder.Props, (size_t)propsSize);
\r
427 if ((mainByte & 0x80) != 0)
\r
428 ThrowUnsupported();
\r
430 numInStreams += coder.NumInStreams;
\r
431 numOutStreams += coder.NumOutStreams;
\r
434 CNum numBindPairs = numOutStreams - 1;
\r
435 folder.BindPairs.Clear();
\r
436 folder.BindPairs.Reserve(numBindPairs);
\r
437 for (i = 0; i < numBindPairs; i++)
\r
440 bp.InIndex = ReadNum();
\r
441 bp.OutIndex = ReadNum();
\r
442 folder.BindPairs.Add(bp);
\r
445 if (numInStreams < numBindPairs)
\r
446 ThrowUnsupported();
\r
447 CNum numPackStreams = numInStreams - numBindPairs;
\r
448 folder.PackStreams.Reserve(numPackStreams);
\r
449 if (numPackStreams == 1)
\r
451 for (i = 0; i < numInStreams; i++)
\r
452 if (folder.FindBindPairForInStream(i) < 0)
\r
454 folder.PackStreams.Add(i);
\r
457 if (folder.PackStreams.Size() != 1)
\r
458 ThrowUnsupported();
\r
461 for (i = 0; i < numPackStreams; i++)
\r
462 folder.PackStreams.Add(ReadNum());
\r
465 void CInArchive::WaitAttribute(UInt64 attribute)
\r
469 UInt64 type = ReadID();
\r
470 if (type == attribute)
\r
472 if (type == NID::kEnd)
\r
478 void CInArchive::ReadHashDigests(int numItems,
\r
479 CBoolVector &digestsDefined,
\r
480 CRecordVector<UInt32> &digests)
\r
482 ReadBoolVector2(numItems, digestsDefined);
\r
484 digests.Reserve(numItems);
\r
485 for (int i = 0; i < numItems; i++)
\r
488 if (digestsDefined[i])
\r
489 crc = ReadUInt32();
\r
494 void CInArchive::ReadPackInfo(
\r
495 UInt64 &dataOffset,
\r
496 CRecordVector<UInt64> &packSizes,
\r
497 CBoolVector &packCRCsDefined,
\r
498 CRecordVector<UInt32> &packCRCs)
\r
500 dataOffset = ReadNumber();
\r
501 CNum numPackStreams = ReadNum();
\r
503 WaitAttribute(NID::kSize);
\r
505 packSizes.Reserve(numPackStreams);
\r
506 for (CNum i = 0; i < numPackStreams; i++)
\r
507 packSizes.Add(ReadNumber());
\r
513 if (type == NID::kEnd)
\r
515 if (type == NID::kCRC)
\r
517 ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs);
\r
522 if (packCRCsDefined.IsEmpty())
\r
524 BoolVector_Fill_False(packCRCsDefined, numPackStreams);
\r
525 packCRCs.Reserve(numPackStreams);
\r
527 for (CNum i = 0; i < numPackStreams; i++)
\r
532 void CInArchive::ReadUnpackInfo(
\r
533 const CObjectVector<CByteBuffer> *dataVector,
\r
534 CObjectVector<CFolder> &folders)
\r
536 WaitAttribute(NID::kFolder);
\r
537 CNum numFolders = ReadNum();
\r
540 CStreamSwitch streamSwitch;
\r
541 streamSwitch.Set(this, dataVector);
\r
543 folders.Reserve(numFolders);
\r
544 for (CNum i = 0; i < numFolders; i++)
\r
546 folders.Add(CFolder());
\r
547 GetNextFolderItem(folders.Back());
\r
551 WaitAttribute(NID::kCodersUnpackSize);
\r
554 for (i = 0; i < numFolders; i++)
\r
556 CFolder &folder = folders[i];
\r
557 CNum numOutStreams = folder.GetNumOutStreams();
\r
558 folder.UnpackSizes.Reserve(numOutStreams);
\r
559 for (CNum j = 0; j < numOutStreams; j++)
\r
560 folder.UnpackSizes.Add(ReadNumber());
\r
565 UInt64 type = ReadID();
\r
566 if (type == NID::kEnd)
\r
568 if (type == NID::kCRC)
\r
570 CBoolVector crcsDefined;
\r
571 CRecordVector<UInt32> crcs;
\r
572 ReadHashDigests(numFolders, crcsDefined, crcs);
\r
573 for (i = 0; i < numFolders; i++)
\r
575 CFolder &folder = folders[i];
\r
576 folder.UnpackCRCDefined = crcsDefined[i];
\r
577 folder.UnpackCRC = crcs[i];
\r
585 void CInArchive::ReadSubStreamsInfo(
\r
586 const CObjectVector<CFolder> &folders,
\r
587 CRecordVector<CNum> &numUnpackStreamsInFolders,
\r
588 CRecordVector<UInt64> &unpackSizes,
\r
589 CBoolVector &digestsDefined,
\r
590 CRecordVector<UInt32> &digests)
\r
592 numUnpackStreamsInFolders.Clear();
\r
593 numUnpackStreamsInFolders.Reserve(folders.Size());
\r
598 if (type == NID::kNumUnpackStream)
\r
600 for (int i = 0; i < folders.Size(); i++)
\r
601 numUnpackStreamsInFolders.Add(ReadNum());
\r
604 if (type == NID::kCRC || type == NID::kSize)
\r
606 if (type == NID::kEnd)
\r
611 if (numUnpackStreamsInFolders.IsEmpty())
\r
612 for (int i = 0; i < folders.Size(); i++)
\r
613 numUnpackStreamsInFolders.Add(1);
\r
616 for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
\r
618 // v3.13 incorrectly worked with empty folders
\r
619 // v4.07: we check that folder is empty
\r
620 CNum numSubstreams = numUnpackStreamsInFolders[i];
\r
621 if (numSubstreams == 0)
\r
624 for (CNum j = 1; j < numSubstreams; j++)
\r
625 if (type == NID::kSize)
\r
627 UInt64 size = ReadNumber();
\r
628 unpackSizes.Add(size);
\r
631 unpackSizes.Add(folders[i].GetUnpackSize() - sum);
\r
633 if (type == NID::kSize)
\r
636 int numDigests = 0;
\r
637 int numDigestsTotal = 0;
\r
638 for (i = 0; i < folders.Size(); i++)
\r
640 CNum numSubstreams = numUnpackStreamsInFolders[i];
\r
641 if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
\r
642 numDigests += numSubstreams;
\r
643 numDigestsTotal += numSubstreams;
\r
648 if (type == NID::kCRC)
\r
650 CBoolVector digestsDefined2;
\r
651 CRecordVector<UInt32> digests2;
\r
652 ReadHashDigests(numDigests, digestsDefined2, digests2);
\r
653 int digestIndex = 0;
\r
654 for (i = 0; i < folders.Size(); i++)
\r
656 CNum numSubstreams = numUnpackStreamsInFolders[i];
\r
657 const CFolder &folder = folders[i];
\r
658 if (numSubstreams == 1 && folder.UnpackCRCDefined)
\r
660 digestsDefined.Add(true);
\r
661 digests.Add(folder.UnpackCRC);
\r
664 for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
\r
666 digestsDefined.Add(digestsDefined2[digestIndex]);
\r
667 digests.Add(digests2[digestIndex]);
\r
671 else if (type == NID::kEnd)
\r
673 if (digestsDefined.IsEmpty())
\r
675 BoolVector_Fill_False(digestsDefined, numDigestsTotal);
\r
677 for (int i = 0; i < numDigestsTotal; i++)
\r
688 void CInArchive::ReadStreamsInfo(
\r
689 const CObjectVector<CByteBuffer> *dataVector,
\r
690 UInt64 &dataOffset,
\r
691 CRecordVector<UInt64> &packSizes,
\r
692 CBoolVector &packCRCsDefined,
\r
693 CRecordVector<UInt32> &packCRCs,
\r
694 CObjectVector<CFolder> &folders,
\r
695 CRecordVector<CNum> &numUnpackStreamsInFolders,
\r
696 CRecordVector<UInt64> &unpackSizes,
\r
697 CBoolVector &digestsDefined,
\r
698 CRecordVector<UInt32> &digests)
\r
702 UInt64 type = ReadID();
\r
703 if (type > ((UInt32)1 << 30))
\r
705 switch((UInt32)type)
\r
709 case NID::kPackInfo:
\r
711 ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
\r
714 case NID::kUnpackInfo:
\r
716 ReadUnpackInfo(dataVector, folders);
\r
719 case NID::kSubStreamsInfo:
\r
721 ReadSubStreamsInfo(folders, numUnpackStreamsInFolders,
\r
722 unpackSizes, digestsDefined, digests);
\r
731 void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
\r
734 v.Reserve(numItems);
\r
737 for (int i = 0; i < numItems; i++)
\r
744 v.Add((b & mask) != 0);
\r
749 void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
\r
751 Byte allAreDefined = ReadByte();
\r
752 if (allAreDefined == 0)
\r
754 ReadBoolVector(numItems, v);
\r
758 v.Reserve(numItems);
\r
759 for (int i = 0; i < numItems; i++)
\r
763 void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
\r
764 CUInt64DefVector &v, int numFiles)
\r
766 ReadBoolVector2(numFiles, v.Defined);
\r
768 CStreamSwitch streamSwitch;
\r
769 streamSwitch.Set(this, &dataVector);
\r
770 v.Values.Reserve(numFiles);
\r
772 for (int i = 0; i < numFiles; i++)
\r
781 HRESULT CInArchive::ReadAndDecodePackedStreams(
\r
782 DECL_EXTERNAL_CODECS_LOC_VARS
\r
784 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
\r
786 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
\r
790 CRecordVector<UInt64> packSizes;
\r
791 CBoolVector packCRCsDefined;
\r
792 CRecordVector<UInt32> packCRCs;
\r
793 CObjectVector<CFolder> folders;
\r
795 CRecordVector<CNum> numUnpackStreamsInFolders;
\r
796 CRecordVector<UInt64> unpackSizes;
\r
797 CBoolVector digestsDefined;
\r
798 CRecordVector<UInt32> digests;
\r
800 ReadStreamsInfo(NULL,
\r
806 numUnpackStreamsInFolders,
\r
811 // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
\r
813 CNum packIndex = 0;
\r
821 UInt64 dataStartPos = baseOffset + dataOffset;
\r
822 for (int i = 0; i < folders.Size(); i++)
\r
824 const CFolder &folder = folders[i];
\r
825 dataVector.Add(CByteBuffer());
\r
826 CByteBuffer &data = dataVector.Back();
\r
827 UInt64 unpackSize64 = folder.GetUnpackSize();
\r
828 size_t unpackSize = (size_t)unpackSize64;
\r
829 if (unpackSize != unpackSize64)
\r
830 ThrowUnsupported();
\r
831 data.SetCapacity(unpackSize);
\r
833 CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
\r
834 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
\r
835 outStreamSpec->Init(data, unpackSize);
\r
837 HRESULT result = decoder.Decode(
\r
838 EXTERNAL_CODECS_LOC_VARS
\r
839 _stream, dataStartPos,
\r
840 &packSizes[packIndex], folder, outStream, NULL
\r
842 , getTextPassword, passwordIsDefined
\r
844 #if !defined(_7ZIP_ST) && !defined(_SFX)
\r
850 if (folder.UnpackCRCDefined)
\r
851 if (CrcCalc(data, unpackSize) != folder.UnpackCRC)
\r
853 for (int j = 0; j < folder.PackStreams.Size(); j++)
\r
855 UInt64 packSize = packSizes[packIndex++];
\r
856 dataStartPos += packSize;
\r
857 HeadersSize += packSize;
\r
863 HRESULT CInArchive::ReadHeader(
\r
864 DECL_EXTERNAL_CODECS_LOC_VARS
\r
865 CArchiveDatabaseEx &db
\r
867 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
\r
871 UInt64 type = ReadID();
\r
873 if (type == NID::kArchiveProperties)
\r
875 ReadArchiveProperties(db.ArchiveInfo);
\r
879 CObjectVector<CByteBuffer> dataVector;
\r
881 if (type == NID::kAdditionalStreamsInfo)
\r
883 HRESULT result = ReadAndDecodePackedStreams(
\r
884 EXTERNAL_CODECS_LOC_VARS
\r
885 db.ArchiveInfo.StartPositionAfterHeader,
\r
886 db.ArchiveInfo.DataStartPosition2,
\r
889 , getTextPassword, passwordIsDefined
\r
893 db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
\r
897 CRecordVector<UInt64> unpackSizes;
\r
898 CBoolVector digestsDefined;
\r
899 CRecordVector<UInt32> digests;
\r
901 if (type == NID::kMainStreamsInfo)
\r
903 ReadStreamsInfo(&dataVector,
\r
904 db.ArchiveInfo.DataStartPosition,
\r
906 db.PackCRCsDefined,
\r
909 db.NumUnpackStreamsVector,
\r
913 db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader;
\r
918 for (int i = 0; i < db.Folders.Size(); i++)
\r
920 db.NumUnpackStreamsVector.Add(1);
\r
921 CFolder &folder = db.Folders[i];
\r
922 unpackSizes.Add(folder.GetUnpackSize());
\r
923 digestsDefined.Add(folder.UnpackCRCDefined);
\r
924 digests.Add(folder.UnpackCRC);
\r
930 if (type == NID::kEnd)
\r
932 if (type != NID::kFilesInfo)
\r
935 CNum numFiles = ReadNum();
\r
936 db.Files.Reserve(numFiles);
\r
938 for (i = 0; i < numFiles; i++)
\r
939 db.Files.Add(CFileItem());
\r
941 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
\r
942 if (!db.PackSizes.IsEmpty())
\r
943 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
\r
944 if (numFiles > 0 && !digests.IsEmpty())
\r
945 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
\r
947 CBoolVector emptyStreamVector;
\r
948 BoolVector_Fill_False(emptyStreamVector, (int)numFiles);
\r
949 CBoolVector emptyFileVector;
\r
950 CBoolVector antiFileVector;
\r
951 CNum numEmptyStreams = 0;
\r
955 UInt64 type = ReadID();
\r
956 if (type == NID::kEnd)
\r
958 UInt64 size = ReadNumber();
\r
959 size_t ppp = _inByteBack->_pos;
\r
960 bool addPropIdToList = true;
\r
961 bool isKnownType = true;
\r
962 if (type > ((UInt32)1 << 30))
\r
963 isKnownType = false;
\r
964 else switch((UInt32)type)
\r
968 CStreamSwitch streamSwitch;
\r
969 streamSwitch.Set(this, &dataVector);
\r
970 for (int i = 0; i < db.Files.Size(); i++)
\r
971 _inByteBack->ReadString(db.Files[i].Name);
\r
974 case NID::kWinAttributes:
\r
976 CBoolVector boolVector;
\r
977 ReadBoolVector2(db.Files.Size(), boolVector);
\r
978 CStreamSwitch streamSwitch;
\r
979 streamSwitch.Set(this, &dataVector);
\r
980 for (i = 0; i < numFiles; i++)
\r
982 CFileItem &file = db.Files[i];
\r
983 file.AttribDefined = boolVector[i];
\r
984 if (file.AttribDefined)
\r
985 file.Attrib = ReadUInt32();
\r
989 case NID::kEmptyStream:
\r
991 ReadBoolVector(numFiles, emptyStreamVector);
\r
992 for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
\r
993 if (emptyStreamVector[i])
\r
996 BoolVector_Fill_False(emptyFileVector, numEmptyStreams);
\r
997 BoolVector_Fill_False(antiFileVector, numEmptyStreams);
\r
1001 case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break;
\r
1002 case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break;
\r
1003 case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break;
\r
1004 case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break;
\r
1005 case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break;
\r
1006 case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break;
\r
1009 for (UInt64 j = 0; j < size; j++)
\r
1010 if (ReadByte() != 0)
\r
1012 addPropIdToList = false;
\r
1016 addPropIdToList = isKnownType = false;
\r
1020 if(addPropIdToList)
\r
1021 db.ArchiveInfo.FileInfoPopIDs.Add(type);
\r
1025 bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 ||
\r
1026 db.ArchiveInfo.Version.Minor > 2);
\r
1027 if (checkRecordsSize && _inByteBack->_pos - ppp != size)
\r
1031 CNum emptyFileIndex = 0;
\r
1032 CNum sizeIndex = 0;
\r
1034 CNum numAntiItems = 0;
\r
1035 for (i = 0; i < numEmptyStreams; i++)
\r
1036 if (antiFileVector[i])
\r
1039 for (i = 0; i < numFiles; i++)
\r
1041 CFileItem &file = db.Files[i];
\r
1043 file.HasStream = !emptyStreamVector[i];
\r
1044 if (file.HasStream)
\r
1046 file.IsDir = false;
\r
1048 file.Size = unpackSizes[sizeIndex];
\r
1049 file.Crc = digests[sizeIndex];
\r
1050 file.CrcDefined = digestsDefined[sizeIndex];
\r
1055 file.IsDir = !emptyFileVector[emptyFileIndex];
\r
1056 isAnti = antiFileVector[emptyFileIndex];
\r
1059 file.CrcDefined = false;
\r
1061 if (numAntiItems != 0)
\r
1062 db.IsAnti.Add(isAnti);
\r
1068 void CArchiveDatabaseEx::FillFolderStartPackStream()
\r
1070 FolderStartPackStreamIndex.Clear();
\r
1071 FolderStartPackStreamIndex.Reserve(Folders.Size());
\r
1072 CNum startPos = 0;
\r
1073 for (int i = 0; i < Folders.Size(); i++)
\r
1075 FolderStartPackStreamIndex.Add(startPos);
\r
1076 startPos += (CNum)Folders[i].PackStreams.Size();
\r
1080 void CArchiveDatabaseEx::FillStartPos()
\r
1082 PackStreamStartPositions.Clear();
\r
1083 PackStreamStartPositions.Reserve(PackSizes.Size());
\r
1084 UInt64 startPos = 0;
\r
1085 for (int i = 0; i < PackSizes.Size(); i++)
\r
1087 PackStreamStartPositions.Add(startPos);
\r
1088 startPos += PackSizes[i];
\r
1092 void CArchiveDatabaseEx::FillFolderStartFileIndex()
\r
1094 FolderStartFileIndex.Clear();
\r
1095 FolderStartFileIndex.Reserve(Folders.Size());
\r
1096 FileIndexToFolderIndexMap.Clear();
\r
1097 FileIndexToFolderIndexMap.Reserve(Files.Size());
\r
1099 int folderIndex = 0;
\r
1100 CNum indexInFolder = 0;
\r
1101 for (int i = 0; i < Files.Size(); i++)
\r
1103 const CFileItem &file = Files[i];
\r
1104 bool emptyStream = !file.HasStream;
\r
1105 if (emptyStream && indexInFolder == 0)
\r
1107 FileIndexToFolderIndexMap.Add(kNumNoIndex);
\r
1110 if (indexInFolder == 0)
\r
1112 // v3.13 incorrectly worked with empty folders
\r
1113 // v4.07: Loop for skipping empty folders
\r
1116 if (folderIndex >= Folders.Size())
\r
1118 FolderStartFileIndex.Add(i); // check it
\r
1119 if (NumUnpackStreamsVector[folderIndex] != 0)
\r
1124 FileIndexToFolderIndexMap.Add(folderIndex);
\r
1128 if (indexInFolder >= NumUnpackStreamsVector[folderIndex])
\r
1131 indexInFolder = 0;
\r
1136 HRESULT CInArchive::ReadDatabase2(
\r
1137 DECL_EXTERNAL_CODECS_LOC_VARS
\r
1138 CArchiveDatabaseEx &db
\r
1139 #ifndef _NO_CRYPTO
\r
1140 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
\r
1145 db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
\r
1147 db.ArchiveInfo.Version.Major = _header[6];
\r
1148 db.ArchiveInfo.Version.Minor = _header[7];
\r
1150 if (db.ArchiveInfo.Version.Major != kMajorVersion)
\r
1151 ThrowUnsupportedVersion();
\r
1153 UInt32 crcFromArchive = Get32(_header + 8);
\r
1154 UInt64 nextHeaderOffset = Get64(_header + 0xC);
\r
1155 UInt64 nextHeaderSize = Get64(_header + 0x14);
\r
1156 UInt32 nextHeaderCRC = Get32(_header + 0x1C);
\r
1157 UInt32 crc = CrcCalc(_header + 0xC, 20);
\r
1159 #ifdef FORMAT_7Z_RECOVERY
\r
1160 if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
\r
1163 RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
\r
1164 const int kCheckSize = 500;
\r
1165 Byte buf[kCheckSize];
\r
1166 RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
\r
1167 int checkSize = kCheckSize;
\r
1168 if (cur2 - cur < kCheckSize)
\r
1169 checkSize = (int)(cur2 - cur);
\r
1170 RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
\r
1172 RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));
\r
1175 for (i = (int)checkSize - 2; i >= 0; i--)
\r
1176 if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
\r
1180 nextHeaderSize = checkSize - i;
\r
1181 nextHeaderOffset = cur2 - cur + i;
\r
1182 nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
\r
1183 RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
\r
1188 if (crc != crcFromArchive)
\r
1192 db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
\r
1194 if (nextHeaderSize == 0)
\r
1197 if (nextHeaderSize > (UInt64)0xFFFFFFFF)
\r
1200 if ((Int64)nextHeaderOffset < 0)
\r
1203 RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
\r
1205 CByteBuffer buffer2;
\r
1206 buffer2.SetCapacity((size_t)nextHeaderSize);
\r
1208 RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize));
\r
1209 HeadersSize += kHeaderSize + nextHeaderSize;
\r
1210 db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
\r
1212 if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
\r
1215 CStreamSwitch streamSwitch;
\r
1216 streamSwitch.Set(this, buffer2);
\r
1218 CObjectVector<CByteBuffer> dataVector;
\r
1220 UInt64 type = ReadID();
\r
1221 if (type != NID::kHeader)
\r
1223 if (type != NID::kEncodedHeader)
\r
1225 HRESULT result = ReadAndDecodePackedStreams(
\r
1226 EXTERNAL_CODECS_LOC_VARS
\r
1227 db.ArchiveInfo.StartPositionAfterHeader,
\r
1228 db.ArchiveInfo.DataStartPosition2,
\r
1230 #ifndef _NO_CRYPTO
\r
1231 , getTextPassword, passwordIsDefined
\r
1235 if (dataVector.Size() == 0)
\r
1237 if (dataVector.Size() > 1)
\r
1239 streamSwitch.Remove();
\r
1240 streamSwitch.Set(this, dataVector.Front());
\r
1241 if (ReadID() != NID::kHeader)
\r
1245 db.HeadersSize = HeadersSize;
\r
1247 return ReadHeader(
\r
1248 EXTERNAL_CODECS_LOC_VARS
\r
1250 #ifndef _NO_CRYPTO
\r
1251 , getTextPassword, passwordIsDefined
\r
1256 HRESULT CInArchive::ReadDatabase(
\r
1257 DECL_EXTERNAL_CODECS_LOC_VARS
\r
1258 CArchiveDatabaseEx &db
\r
1259 #ifndef _NO_CRYPTO
\r
1260 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
\r
1266 return ReadDatabase2(
\r
1267 EXTERNAL_CODECS_LOC_VARS db
\r
1268 #ifndef _NO_CRYPTO
\r
1269 , getTextPassword, passwordIsDefined
\r
1273 catch(CInArchiveException &) { return S_FALSE; }
\r