7 #include "../../Common/StreamObjects.h"
8 #include "../../Common/StreamUtils.h"
11 #include "../../../../C/7zCrc.h"
14 // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader
16 #define FORMAT_7Z_RECOVERY
22 class CInArchiveException {};
24 static void ThrowException() { throw CInArchiveException(); }
25 static inline void ThrowEndOfData() { ThrowException(); }
26 static inline void ThrowUnsupported() { ThrowException(); }
27 static inline void ThrowIncorrect() { ThrowException(); }
28 static inline void ThrowUnsupportedVersion() { ThrowException(); }
31 class CInArchiveException
36 kUnsupportedVersion = 0,
41 CInArchiveException(CCauseType cause): Cause(cause) {};
44 static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
45 static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); }
46 static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
47 static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); }
48 static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
56 CStreamSwitch(): _needRemove(false) {}
57 ~CStreamSwitch() { Remove(); }
59 void Set(CInArchive *archive, const Byte *data, size_t size);
60 void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
61 void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
64 void CStreamSwitch::Remove()
68 _archive->DeleteByteStream();
73 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
77 _archive->AddByteStream(data, size);
81 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
83 Set(archive, byteBuffer, byteBuffer.GetCapacity());
86 void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
89 Byte external = archive->ReadByte();
92 int dataIndex = (int)archive->ReadNum();
93 if (dataIndex < 0 || dataIndex >= dataVector->Size())
95 Set(archive, (*dataVector)[dataIndex]);
99 #if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
100 #define SZ_LITTLE_ENDIAN_UNALIGN
103 #ifdef SZ_LITTLE_ENDIAN_UNALIGN
104 static inline UInt16 GetUInt16FromMem(const Byte *p) { return *(const UInt16 *)p; }
105 static inline UInt32 GetUInt32FromMem(const Byte *p) { return *(const UInt32 *)p; }
106 static inline UInt64 GetUInt64FromMem(const Byte *p) { return *(const UInt64 *)p; }
108 static inline UInt16 GetUInt16FromMem(const Byte *p) { return p[0] | ((UInt16)p[1] << 8); }
109 static inline UInt32 GetUInt32FromMem(const Byte *p) { return p[0] | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16) | ((UInt32)p[3] << 24); }
110 static inline UInt64 GetUInt64FromMem(const Byte *p) { return GetUInt32FromMem(p) | ((UInt64)GetUInt32FromMem(p + 4) << 32); }
113 Byte CInByte2::ReadByte()
117 return _buffer[_pos++];
120 void CInByte2::ReadBytes(Byte *data, size_t size)
122 if (size > _size - _pos)
124 for (size_t i = 0; i < size; i++)
125 data[i] = _buffer[_pos++];
128 void CInByte2::SkeepData(UInt64 size)
130 if (size > _size - _pos)
134 void CInByte2::SkeepData()
136 SkeepData(ReadNumber());
139 UInt64 CInByte2::ReadNumber()
143 Byte firstByte = _buffer[_pos++];
146 for (int i = 0; i < 8; i++)
148 if ((firstByte & mask) == 0)
150 UInt64 highPart = firstByte & (mask - 1);
151 value += (highPart << (i * 8));
156 value |= ((UInt64)_buffer[_pos++] << (8 * i));
162 CNum CInByte2::ReadNum()
164 UInt64 value = ReadNumber();
170 UInt32 CInByte2::ReadUInt32()
172 if (_pos + 4 > _size)
174 UInt32 res = GetUInt32FromMem(_buffer + _pos);
179 UInt64 CInByte2::ReadUInt64()
181 if (_pos + 8 > _size)
183 UInt64 res = GetUInt64FromMem(_buffer + _pos);
188 void CInByte2::ReadString(UString &s)
190 const Byte *buf = _buffer + _pos;
191 size_t rem = (_size - _pos) / 2 * 2;
194 for (i = 0; i < rem; i += 2)
195 if (buf[i] == 0 && buf[i + 1] == 0)
201 int len = (int)(rem / 2);
202 if (len < 0 || (size_t)len * 2 != rem)
204 wchar_t *p = s.GetBuffer(len);
206 for (i = 0; i < len; i++, buf += 2)
207 p[i] = (wchar_t)GetUInt16FromMem(buf);
209 s.ReleaseBuffer(len);
213 static inline bool TestSignatureCandidate(const Byte *p)
215 for (int i = 0; i < kSignatureSize; i++)
216 if (p[i] != kSignature[i])
218 return (p[0x1A] == 0 && p[0x1B] == 0);
221 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
223 UInt32 processedSize;
224 RINOK(ReadStream(stream, _header, kHeaderSize, &processedSize));
225 if (processedSize != kHeaderSize)
227 if (TestSignatureCandidate(_header))
230 CByteBuffer byteBuffer;
231 const UInt32 kBufferSize = (1 << 16);
232 byteBuffer.SetCapacity(kBufferSize);
233 Byte *buffer = byteBuffer;
234 UInt32 numPrevBytes = kHeaderSize - 1;
235 memcpy(buffer, _header + 1, numPrevBytes);
236 UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
239 if (searchHeaderSizeLimit != NULL)
240 if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
242 UInt32 numReadBytes = kBufferSize - numPrevBytes;
243 RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
244 UInt32 numBytesInBuffer = numPrevBytes + processedSize;
245 if (numBytesInBuffer < kHeaderSize)
247 UInt32 numTests = numBytesInBuffer - kHeaderSize + 1;
248 for(UInt32 pos = 0; pos < numTests; pos++, curTestPos++)
250 if (TestSignatureCandidate(buffer + pos))
252 memcpy(_header, buffer + pos, kHeaderSize);
253 _arhiveBeginStreamPosition = curTestPos;
254 return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
257 numPrevBytes = numBytesInBuffer - numTests;
258 memmove(buffer, buffer + numTests, numPrevBytes);
263 // S_FALSE means that file is not archive
264 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
267 RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
268 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
273 void CInArchive::Close()
278 void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
282 if (ReadID() == NID::kEnd)
288 void CInArchive::GetNextFolderItem(CFolder &folder)
290 CNum numCoders = ReadNum();
292 folder.Coders.Clear();
293 folder.Coders.Reserve((int)numCoders);
294 CNum numInStreams = 0;
295 CNum numOutStreams = 0;
297 for (i = 0; i < numCoders; i++)
299 folder.Coders.Add(CCoderInfo());
300 CCoderInfo &coder = folder.Coders.Back();
303 Byte mainByte = ReadByte();
304 int idSize = (mainByte & 0xF);
306 ReadBytes(longID, idSize);
310 for (int j = 0; j < idSize; j++)
311 id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
314 if ((mainByte & 0x10) != 0)
316 coder.NumInStreams = ReadNum();
317 coder.NumOutStreams = ReadNum();
321 coder.NumInStreams = 1;
322 coder.NumOutStreams = 1;
324 if ((mainByte & 0x20) != 0)
326 CNum propertiesSize = ReadNum();
327 coder.Properties.SetCapacity((size_t)propertiesSize);
328 ReadBytes((Byte *)coder.Properties, (size_t)propertiesSize);
330 if ((mainByte & 0x80) != 0)
333 numInStreams += coder.NumInStreams;
334 numOutStreams += coder.NumOutStreams;
338 numBindPairs = numOutStreams - 1;
339 folder.BindPairs.Clear();
340 folder.BindPairs.Reserve(numBindPairs);
341 for (i = 0; i < numBindPairs; i++)
344 bindPair.InIndex = ReadNum();
345 bindPair.OutIndex = ReadNum();
346 folder.BindPairs.Add(bindPair);
349 CNum numPackedStreams = numInStreams - numBindPairs;
350 folder.PackStreams.Reserve(numPackedStreams);
351 if (numPackedStreams == 1)
353 for (CNum j = 0; j < numInStreams; j++)
354 if (folder.FindBindPairForInStream(j) < 0)
356 folder.PackStreams.Add(j);
361 for(i = 0; i < numPackedStreams; i++)
362 folder.PackStreams.Add(ReadNum());
365 void CInArchive::WaitAttribute(UInt64 attribute)
369 UInt64 type = ReadID();
370 if (type == attribute)
372 if (type == NID::kEnd)
378 void CInArchive::ReadHashDigests(int numItems,
379 CRecordVector<bool> &digestsDefined,
380 CRecordVector<UInt32> &digests)
382 ReadBoolVector2(numItems, digestsDefined);
384 digests.Reserve(numItems);
385 for(int i = 0; i < numItems; i++)
388 if (digestsDefined[i])
394 void CInArchive::ReadPackInfo(
396 CRecordVector<UInt64> &packSizes,
397 CRecordVector<bool> &packCRCsDefined,
398 CRecordVector<UInt32> &packCRCs)
400 dataOffset = ReadNumber();
401 CNum numPackStreams = ReadNum();
403 WaitAttribute(NID::kSize);
405 packSizes.Reserve(numPackStreams);
406 for (CNum i = 0; i < numPackStreams; i++)
407 packSizes.Add(ReadNumber());
413 if (type == NID::kEnd)
415 if (type == NID::kCRC)
417 ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs);
422 if (packCRCsDefined.IsEmpty())
424 packCRCsDefined.Reserve(numPackStreams);
425 packCRCsDefined.Clear();
426 packCRCs.Reserve(numPackStreams);
428 for(CNum i = 0; i < numPackStreams; i++)
430 packCRCsDefined.Add(false);
436 void CInArchive::ReadUnPackInfo(
437 const CObjectVector<CByteBuffer> *dataVector,
438 CObjectVector<CFolder> &folders)
440 WaitAttribute(NID::kFolder);
441 CNum numFolders = ReadNum();
444 CStreamSwitch streamSwitch;
445 streamSwitch.Set(this, dataVector);
447 folders.Reserve(numFolders);
448 for(CNum i = 0; i < numFolders; i++)
450 folders.Add(CFolder());
451 GetNextFolderItem(folders.Back());
455 WaitAttribute(NID::kCodersUnPackSize);
458 for (i = 0; i < numFolders; i++)
460 CFolder &folder = folders[i];
461 CNum numOutStreams = folder.GetNumOutStreams();
462 folder.UnPackSizes.Reserve(numOutStreams);
463 for (CNum j = 0; j < numOutStreams; j++)
464 folder.UnPackSizes.Add(ReadNumber());
469 UInt64 type = ReadID();
470 if (type == NID::kEnd)
472 if (type == NID::kCRC)
474 CRecordVector<bool> crcsDefined;
475 CRecordVector<UInt32> crcs;
476 ReadHashDigests(numFolders, crcsDefined, crcs);
477 for(i = 0; i < numFolders; i++)
479 CFolder &folder = folders[i];
480 folder.UnPackCRCDefined = crcsDefined[i];
481 folder.UnPackCRC = crcs[i];
489 void CInArchive::ReadSubStreamsInfo(
490 const CObjectVector<CFolder> &folders,
491 CRecordVector<CNum> &numUnPackStreamsInFolders,
492 CRecordVector<UInt64> &unPackSizes,
493 CRecordVector<bool> &digestsDefined,
494 CRecordVector<UInt32> &digests)
496 numUnPackStreamsInFolders.Clear();
497 numUnPackStreamsInFolders.Reserve(folders.Size());
502 if (type == NID::kNumUnPackStream)
504 for(int i = 0; i < folders.Size(); i++)
505 numUnPackStreamsInFolders.Add(ReadNum());
508 if (type == NID::kCRC || type == NID::kSize)
510 if (type == NID::kEnd)
515 if (numUnPackStreamsInFolders.IsEmpty())
516 for(int i = 0; i < folders.Size(); i++)
517 numUnPackStreamsInFolders.Add(1);
520 for(i = 0; i < numUnPackStreamsInFolders.Size(); i++)
522 // v3.13 incorrectly worked with empty folders
523 // v4.07: we check that folder is empty
524 CNum numSubstreams = numUnPackStreamsInFolders[i];
525 if (numSubstreams == 0)
528 for (CNum j = 1; j < numSubstreams; j++)
529 if (type == NID::kSize)
531 UInt64 size = ReadNumber();
532 unPackSizes.Add(size);
535 unPackSizes.Add(folders[i].GetUnPackSize() - sum);
537 if (type == NID::kSize)
541 int numDigestsTotal = 0;
542 for(i = 0; i < folders.Size(); i++)
544 CNum numSubstreams = numUnPackStreamsInFolders[i];
545 if (numSubstreams != 1 || !folders[i].UnPackCRCDefined)
546 numDigests += numSubstreams;
547 numDigestsTotal += numSubstreams;
552 if (type == NID::kCRC)
554 CRecordVector<bool> digestsDefined2;
555 CRecordVector<UInt32> digests2;
556 ReadHashDigests(numDigests, digestsDefined2, digests2);
558 for (i = 0; i < folders.Size(); i++)
560 CNum numSubstreams = numUnPackStreamsInFolders[i];
561 const CFolder &folder = folders[i];
562 if (numSubstreams == 1 && folder.UnPackCRCDefined)
564 digestsDefined.Add(true);
565 digests.Add(folder.UnPackCRC);
568 for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
570 digestsDefined.Add(digestsDefined2[digestIndex]);
571 digests.Add(digests2[digestIndex]);
575 else if (type == NID::kEnd)
577 if (digestsDefined.IsEmpty())
579 digestsDefined.Clear();
581 for (int i = 0; i < numDigestsTotal; i++)
583 digestsDefined.Add(false);
595 void CInArchive::ReadStreamsInfo(
596 const CObjectVector<CByteBuffer> *dataVector,
598 CRecordVector<UInt64> &packSizes,
599 CRecordVector<bool> &packCRCsDefined,
600 CRecordVector<UInt32> &packCRCs,
601 CObjectVector<CFolder> &folders,
602 CRecordVector<CNum> &numUnPackStreamsInFolders,
603 CRecordVector<UInt64> &unPackSizes,
604 CRecordVector<bool> &digestsDefined,
605 CRecordVector<UInt32> &digests)
609 UInt64 type = ReadID();
610 if (type > ((UInt32)1 << 30))
618 ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
621 case NID::kUnPackInfo:
623 ReadUnPackInfo(dataVector, folders);
626 case NID::kSubStreamsInfo:
628 ReadSubStreamsInfo(folders, numUnPackStreamsInFolders,
629 unPackSizes, digestsDefined, digests);
638 void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
644 for(int i = 0; i < numItems; i++)
651 v.Add((b & mask) != 0);
656 void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
658 Byte allAreDefined = ReadByte();
659 if (allAreDefined == 0)
661 ReadBoolVector(numItems, v);
666 for (int i = 0; i < numItems; i++)
670 void CInArchive::ReadTime(const CObjectVector<CByteBuffer> &dataVector,
671 CObjectVector<CFileItem> &files, UInt32 type)
673 CBoolVector boolVector;
674 ReadBoolVector2(files.Size(), boolVector);
676 CStreamSwitch streamSwitch;
677 streamSwitch.Set(this, &dataVector);
679 for(int i = 0; i < files.Size(); i++)
681 CFileItem &file = files[i];
682 CArchiveFileTime fileTime;
683 fileTime.dwLowDateTime = 0;
684 fileTime.dwHighDateTime = 0;
685 bool defined = boolVector[i];
688 fileTime.dwLowDateTime = ReadUInt32();
689 fileTime.dwHighDateTime = ReadUInt32();
693 case NID::kCreationTime:
694 file.IsCreationTimeDefined = defined;
696 file.CreationTime = fileTime;
698 case NID::kLastWriteTime:
699 file.IsLastWriteTimeDefined = defined;
701 file.LastWriteTime = fileTime;
703 case NID::kLastAccessTime:
704 file.IsLastAccessTimeDefined = defined;
706 file.LastAccessTime = fileTime;
712 HRESULT CInArchive::ReadAndDecodePackedStreams(
713 DECL_EXTERNAL_CODECS_LOC_VARS
715 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
717 , ICryptoGetTextPassword *getTextPassword
721 CRecordVector<UInt64> packSizes;
722 CRecordVector<bool> packCRCsDefined;
723 CRecordVector<UInt32> packCRCs;
724 CObjectVector<CFolder> folders;
726 CRecordVector<CNum> numUnPackStreamsInFolders;
727 CRecordVector<UInt64> unPackSizes;
728 CRecordVector<bool> digestsDefined;
729 CRecordVector<UInt32> digests;
731 ReadStreamsInfo(NULL,
737 numUnPackStreamsInFolders,
742 // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
752 UInt64 dataStartPos = baseOffset + dataOffset;
753 for(int i = 0; i < folders.Size(); i++)
755 const CFolder &folder = folders[i];
756 dataVector.Add(CByteBuffer());
757 CByteBuffer &data = dataVector.Back();
758 UInt64 unPackSize64 = folder.GetUnPackSize();
759 size_t unPackSize = (size_t)unPackSize64;
760 if (unPackSize != unPackSize64)
762 data.SetCapacity(unPackSize);
764 CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
765 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
766 outStreamSpec->Init(data, unPackSize);
768 HRESULT result = decoder.Decode(
769 EXTERNAL_CODECS_LOC_VARS
770 _stream, dataStartPos,
771 &packSizes[packIndex], folder, outStream, NULL
781 if (folder.UnPackCRCDefined)
782 if (CrcCalc(data, unPackSize) != folder.UnPackCRC)
784 for (int j = 0; j < folder.PackStreams.Size(); j++)
785 dataStartPos += packSizes[packIndex++];
790 HRESULT CInArchive::ReadHeader(
791 DECL_EXTERNAL_CODECS_LOC_VARS
792 CArchiveDatabaseEx &database
794 , ICryptoGetTextPassword *getTextPassword
798 UInt64 type = ReadID();
800 if (type == NID::kArchiveProperties)
802 ReadArchiveProperties(database.ArchiveInfo);
806 CObjectVector<CByteBuffer> dataVector;
808 if (type == NID::kAdditionalStreamsInfo)
810 HRESULT result = ReadAndDecodePackedStreams(
811 EXTERNAL_CODECS_LOC_VARS
812 database.ArchiveInfo.StartPositionAfterHeader,
813 database.ArchiveInfo.DataStartPosition2,
820 database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
824 CRecordVector<UInt64> unPackSizes;
825 CRecordVector<bool> digestsDefined;
826 CRecordVector<UInt32> digests;
828 if (type == NID::kMainStreamsInfo)
830 ReadStreamsInfo(&dataVector,
831 database.ArchiveInfo.DataStartPosition,
833 database.PackCRCsDefined,
836 database.NumUnPackStreamsVector,
840 database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader;
845 for(int i = 0; i < database.Folders.Size(); i++)
847 database.NumUnPackStreamsVector.Add(1);
848 CFolder &folder = database.Folders[i];
849 unPackSizes.Add(folder.GetUnPackSize());
850 digestsDefined.Add(folder.UnPackCRCDefined);
851 digests.Add(folder.UnPackCRC);
855 database.Files.Clear();
857 if (type == NID::kEnd)
859 if (type != NID::kFilesInfo)
862 CNum numFiles = ReadNum();
863 database.Files.Reserve(numFiles);
865 for(i = 0; i < numFiles; i++)
866 database.Files.Add(CFileItem());
868 database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
869 if (!database.PackSizes.IsEmpty())
870 database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
871 if (numFiles > 0 && !digests.IsEmpty())
872 database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
874 CBoolVector emptyStreamVector;
875 emptyStreamVector.Reserve((int)numFiles);
876 for(i = 0; i < numFiles; i++)
877 emptyStreamVector.Add(false);
878 CBoolVector emptyFileVector;
879 CBoolVector antiFileVector;
880 CNum numEmptyStreams = 0;
884 UInt64 type = ReadID();
885 if (type == NID::kEnd)
887 UInt64 size = ReadNumber();
888 bool isKnownType = true;
889 if (type > ((UInt32)1 << 30))
891 else switch((UInt32)type)
895 CStreamSwitch streamSwitch;
896 streamSwitch.Set(this, &dataVector);
897 for(int i = 0; i < database.Files.Size(); i++)
898 _inByteBack->ReadString(database.Files[i].Name);
901 case NID::kWinAttributes:
903 CBoolVector boolVector;
904 ReadBoolVector2(database.Files.Size(), boolVector);
905 CStreamSwitch streamSwitch;
906 streamSwitch.Set(this, &dataVector);
907 for(i = 0; i < numFiles; i++)
909 CFileItem &file = database.Files[i];
910 file.AreAttributesDefined = boolVector[i];
911 if (file.AreAttributesDefined)
912 file.Attributes = ReadUInt32();
918 CBoolVector boolVector;
919 ReadBoolVector2(database.Files.Size(), boolVector);
920 CStreamSwitch streamSwitch;
921 streamSwitch.Set(this, &dataVector);
922 for(i = 0; i < numFiles; i++)
924 CFileItem &file = database.Files[i];
925 file.IsStartPosDefined = boolVector[i];
926 if (file.IsStartPosDefined)
927 file.StartPos = ReadUInt64();
931 case NID::kEmptyStream:
933 ReadBoolVector(numFiles, emptyStreamVector);
934 for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
935 if (emptyStreamVector[i])
937 emptyFileVector.Reserve(numEmptyStreams);
938 antiFileVector.Reserve(numEmptyStreams);
939 for (i = 0; i < numEmptyStreams; i++)
941 emptyFileVector.Add(false);
942 antiFileVector.Add(false);
946 case NID::kEmptyFile:
948 ReadBoolVector(numEmptyStreams, emptyFileVector);
953 ReadBoolVector(numEmptyStreams, antiFileVector);
956 case NID::kCreationTime:
957 case NID::kLastWriteTime:
958 case NID::kLastAccessTime:
960 ReadTime(dataVector, database.Files, (UInt32)type);
967 database.ArchiveInfo.FileInfoPopIDs.Add(type);
972 CNum emptyFileIndex = 0;
974 for(i = 0; i < numFiles; i++)
976 CFileItem &file = database.Files[i];
977 file.HasStream = !emptyStreamVector[i];
980 file.IsDirectory = false;
982 file.UnPackSize = unPackSizes[sizeIndex];
983 file.FileCRC = digests[sizeIndex];
984 file.IsFileCRCDefined = digestsDefined[sizeIndex];
989 file.IsDirectory = !emptyFileVector[emptyFileIndex];
990 file.IsAnti = antiFileVector[emptyFileIndex];
993 file.IsFileCRCDefined = false;
1000 void CArchiveDatabaseEx::FillFolderStartPackStream()
1002 FolderStartPackStreamIndex.Clear();
1003 FolderStartPackStreamIndex.Reserve(Folders.Size());
1005 for(int i = 0; i < Folders.Size(); i++)
1007 FolderStartPackStreamIndex.Add(startPos);
1008 startPos += (CNum)Folders[i].PackStreams.Size();
1012 void CArchiveDatabaseEx::FillStartPos()
1014 PackStreamStartPositions.Clear();
1015 PackStreamStartPositions.Reserve(PackSizes.Size());
1016 UInt64 startPos = 0;
1017 for(int i = 0; i < PackSizes.Size(); i++)
1019 PackStreamStartPositions.Add(startPos);
1020 startPos += PackSizes[i];
1024 void CArchiveDatabaseEx::FillFolderStartFileIndex()
1026 FolderStartFileIndex.Clear();
1027 FolderStartFileIndex.Reserve(Folders.Size());
1028 FileIndexToFolderIndexMap.Clear();
1029 FileIndexToFolderIndexMap.Reserve(Files.Size());
1031 int folderIndex = 0;
1032 CNum indexInFolder = 0;
1033 for (int i = 0; i < Files.Size(); i++)
1035 const CFileItem &file = Files[i];
1036 bool emptyStream = !file.HasStream;
1037 if (emptyStream && indexInFolder == 0)
1039 FileIndexToFolderIndexMap.Add(kNumNoIndex);
1042 if (indexInFolder == 0)
1044 // v3.13 incorrectly worked with empty folders
1045 // v4.07: Loop for skipping empty folders
1048 if (folderIndex >= Folders.Size())
1050 FolderStartFileIndex.Add(i); // check it
1051 if (NumUnPackStreamsVector[folderIndex] != 0)
1056 FileIndexToFolderIndexMap.Add(folderIndex);
1060 if (indexInFolder >= NumUnPackStreamsVector[folderIndex])
1068 HRESULT CInArchive::ReadDatabase2(
1069 DECL_EXTERNAL_CODECS_LOC_VARS
1070 CArchiveDatabaseEx &database
1072 , ICryptoGetTextPassword *getTextPassword
1077 database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
1079 database.ArchiveInfo.Version.Major = _header[6];
1080 database.ArchiveInfo.Version.Minor = _header[7];
1082 if (database.ArchiveInfo.Version.Major != kMajorVersion)
1083 ThrowUnsupportedVersion();
1085 UInt32 crcFromArchive = GetUInt32FromMem(_header + 8);
1086 UInt64 nextHeaderOffset = GetUInt64FromMem(_header + 0xC);
1087 UInt64 nextHeaderSize = GetUInt64FromMem(_header + 0x14);
1088 UInt32 nextHeaderCRC = GetUInt32FromMem(_header + 0x1C);
1089 UInt32 crc = CrcCalc(_header + 0xC, 20);
1091 #ifdef FORMAT_7Z_RECOVERY
1092 if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
1095 RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
1096 const int kCheckSize = 500;
1097 Byte buf[kCheckSize];
1098 RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
1099 int checkSize = kCheckSize;
1100 if (cur2 - cur < kCheckSize)
1101 checkSize = (int)(cur2 - cur);
1102 RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
1104 UInt32 realProcessedSize;
1105 RINOK(_stream->Read(buf, (UInt32)kCheckSize, &realProcessedSize));
1108 for (i = (int)realProcessedSize - 2; i >= 0; i--)
1109 if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
1113 nextHeaderSize = realProcessedSize - i;
1114 nextHeaderOffset = cur2 - cur + i;
1115 nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
1116 RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
1120 #ifdef FORMAT_7Z_RECOVERY
1121 crcFromArchive = crc;
1124 database.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
1126 if (crc != crcFromArchive)
1129 if (nextHeaderSize == 0)
1132 if (nextHeaderSize > (UInt64)0xFFFFFFFF)
1135 RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
1137 CByteBuffer buffer2;
1138 buffer2.SetCapacity((size_t)nextHeaderSize);
1140 UInt32 realProcessedSize;
1141 RINOK(_stream->Read(buffer2, (UInt32)nextHeaderSize, &realProcessedSize));
1142 if (realProcessedSize != (UInt32)nextHeaderSize)
1144 if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
1147 CStreamSwitch streamSwitch;
1148 streamSwitch.Set(this, buffer2);
1150 CObjectVector<CByteBuffer> dataVector;
1154 UInt64 type = ReadID();
1155 if (type == NID::kHeader)
1157 if (type != NID::kEncodedHeader)
1159 HRESULT result = ReadAndDecodePackedStreams(
1160 EXTERNAL_CODECS_LOC_VARS
1161 database.ArchiveInfo.StartPositionAfterHeader,
1162 database.ArchiveInfo.DataStartPosition2,
1169 if (dataVector.Size() == 0)
1171 if (dataVector.Size() > 1)
1173 streamSwitch.Remove();
1174 streamSwitch.Set(this, dataVector.Front());
1178 EXTERNAL_CODECS_LOC_VARS
1186 HRESULT CInArchive::ReadDatabase(
1187 DECL_EXTERNAL_CODECS_LOC_VARS
1188 CArchiveDatabaseEx &database
1190 , ICryptoGetTextPassword *getTextPassword
1196 return ReadDatabase2(
1197 EXTERNAL_CODECS_LOC_VARS database
1203 catch(CInArchiveException &) { return S_FALSE; }