8 #include "../../Common/StreamObjects.h"
9 #include "../../Common/StreamUtils.h"
10 #include "../../../Common/CRC.h"
20 CStreamSwitch(): _needRemove(false) {}
21 ~CStreamSwitch() { Remove(); }
23 void Set(CInArchive
*archive
, const Byte
*data
, size_t size
);
24 void Set(CInArchive
*archive
, const CByteBuffer
&byteBuffer
);
25 HRESULT
Set(CInArchive
*archive
, const CObjectVector
<CByteBuffer
> *dataVector
);
28 void CStreamSwitch::Remove()
32 _archive
->DeleteByteStream();
37 void CStreamSwitch::Set(CInArchive
*archive
, const Byte
*data
, size_t size
)
41 _archive
->AddByteStream(data
, size
);
45 void CStreamSwitch::Set(CInArchive
*archive
, const CByteBuffer
&byteBuffer
)
47 Set(archive
, byteBuffer
, byteBuffer
.GetCapacity());
50 HRESULT
CStreamSwitch::Set(CInArchive
*archive
, const CObjectVector
<CByteBuffer
> *dataVector
)
54 RINOK(archive
->ReadByte(external
));
58 RINOK(archive
->ReadNum(dataIndex
));
59 Set(archive
, (*dataVector
)[dataIndex
]);
65 CInArchiveException::CInArchiveException(CCauseType cause
):
69 HRESULT
CInArchive::ReadDirect(IInStream
*stream
, void *data
, UInt32 size
,
70 UInt32
*processedSize
)
72 UInt32 realProcessedSize
;
73 HRESULT result
= ReadStream(stream
, data
, size
, &realProcessedSize
);
74 if(processedSize
!= NULL
)
75 *processedSize
= realProcessedSize
;
76 _position
+= realProcessedSize
;
80 HRESULT
CInArchive::ReadDirect(void *data
, UInt32 size
, UInt32
*processedSize
)
82 return ReadDirect(_stream
, data
, size
, processedSize
);
85 HRESULT
CInArchive::SafeReadDirect(void *data
, UInt32 size
)
87 UInt32 realProcessedSize
;
88 RINOK(ReadDirect(data
, size
, &realProcessedSize
));
89 if (realProcessedSize
!= size
)
90 throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive
);
94 HRESULT
CInArchive::SafeReadDirectByte(Byte
&b
)
96 return SafeReadDirect(&b
, 1);
99 HRESULT
CInArchive::SafeReadDirectUInt32(UInt32
&value
)
102 for (int i
= 0; i
< 4; i
++)
105 RINOK(SafeReadDirectByte(b
));
106 value
|= (UInt32(b
) << (8 * i
));
111 HRESULT
CInArchive::SafeReadDirectUInt64(UInt64
&value
)
114 for (int i
= 0; i
< 8; i
++)
117 RINOK(SafeReadDirectByte(b
));
118 value
|= (UInt64(b
) << (8 * i
));
123 HRESULT
CInArchive::ReadNumber(UInt64
&value
)
126 RINOK(ReadByte(firstByte
));
129 for (int i
= 0; i
< 8; i
++)
131 if ((firstByte
& mask
) == 0)
133 UInt64 highPart
= firstByte
& (mask
- 1);
134 value
+= (highPart
<< (i
* 8));
139 value
|= (UInt64(b
) << (8 * i
));
145 HRESULT
CInArchive::ReadNum(CNum
&value
)
148 RINOK(ReadNumber(value64
));
149 if (value64
> kNumMax
)
151 value
= (CNum
)value64
;
155 HRESULT
CInArchive::ReadUInt32(UInt32
&value
)
158 for (int i
= 0; i
< 4; i
++)
162 value
|= (UInt32(b
) << (8 * i
));
167 HRESULT
CInArchive::ReadUInt64(UInt64
&value
)
170 for (int i
= 0; i
< 8; i
++)
174 value
|= (UInt64(b
) << (8 * i
));
179 static inline bool TestSignatureCandidate(const void *testBytes
)
181 for (int i
= 0; i
< kSignatureSize
; i
++)
182 if (((const Byte
*)testBytes
)[i
] != kSignature
[i
])
188 static inline bool TestFinishSignatureCandidate(const void *testBytes
)
190 for (int i
= 0; i
< kSignatureSize
; i
++)
191 if (((const Byte
*)testBytes
)[i
] != kFinishSignature
[i
])
197 HRESULT
CInArchive::FindAndReadSignature(IInStream
*stream
, const UInt64
*searchHeaderSizeLimit
)
199 _position
= _arhiveBeginStreamPosition
;
200 RINOK(stream
->Seek(_arhiveBeginStreamPosition
, STREAM_SEEK_SET
, NULL
));
202 Byte signature
[kSignatureSize
];
203 UInt32 processedSize
;
204 RINOK(ReadDirect(stream
, signature
, kSignatureSize
, &processedSize
));
205 if(processedSize
!= kSignatureSize
)
207 if (TestSignatureCandidate(signature
))
210 CByteBuffer byteBuffer
;
211 const UInt32 kBufferSize
= (1 << 16);
212 byteBuffer
.SetCapacity(kBufferSize
);
213 Byte
*buffer
= byteBuffer
;
214 UInt32 numPrevBytes
= kSignatureSize
- 1;
215 memmove(buffer
, signature
+ 1, numPrevBytes
);
216 UInt64 curTestPos
= _arhiveBeginStreamPosition
+ 1;
219 if (searchHeaderSizeLimit
!= NULL
)
220 if (curTestPos
- _arhiveBeginStreamPosition
> *searchHeaderSizeLimit
)
222 UInt32 numReadBytes
= kBufferSize
- numPrevBytes
;
223 RINOK(ReadDirect(stream
, buffer
+ numPrevBytes
, numReadBytes
, &processedSize
));
224 UInt32 numBytesInBuffer
= numPrevBytes
+ processedSize
;
225 if (numBytesInBuffer
< kSignatureSize
)
227 UInt32 numTests
= numBytesInBuffer
- kSignatureSize
+ 1;
228 for(UInt32 pos
= 0; pos
< numTests
; pos
++, curTestPos
++)
230 if (TestSignatureCandidate(buffer
+ pos
))
232 _arhiveBeginStreamPosition
= curTestPos
;
233 _position
= curTestPos
+ kSignatureSize
;
234 return stream
->Seek(_position
, STREAM_SEEK_SET
, NULL
);
237 numPrevBytes
= numBytesInBuffer
- numTests
;
238 memmove(buffer
, buffer
+ numTests
, numPrevBytes
);
242 // Out: _position must point to end of signature
245 HRESULT
CInArchive::FindFinishSignature(IInStream
*stream
, const UInt64
*searchHeaderSizeLimit
)
247 RINOK(stream
->Seek(0, STREAM_SEEK_END
, &_position
));
248 if (_position
< kSignatureSize
)
251 CByteBuffer byteBuffer
;
252 const UInt32 kBufferSize
= (1 << 18);
253 byteBuffer
.SetCapacity(kBufferSize
);
254 Byte
*buffer
= byteBuffer
;
255 UInt32 numPrevBytes
= 0;
257 if (searchHeaderSizeLimit
!= NULL
)
258 if (*searchHeaderSizeLimit
< _position
)
259 limitPos
= _position
- *searchHeaderSizeLimit
;
261 while(_position
>= limitPos
)
263 UInt32 numReadBytes
= kBufferSize
- numPrevBytes
;
264 if (numReadBytes
> _position
)
265 numReadBytes
= (UInt32
)_position
;
266 UInt32 numBytesInBuffer
= numPrevBytes
+ numReadBytes
;
267 if (numBytesInBuffer
< kSignatureSize
)
269 _position
-= numReadBytes
;
270 RINOK(stream
->Seek(_position
, STREAM_SEEK_SET
, &_position
));
271 UInt32 startPos
= kBufferSize
- numBytesInBuffer
;
272 UInt32 processedSize
;
273 RINOK(ReadDirect(stream
, buffer
+ startPos
, numReadBytes
, &processedSize
));
274 if (processedSize
!= numReadBytes
)
276 _position
-= processedSize
;
277 for(UInt32 pos
= kBufferSize
; pos
>= startPos
+ kSignatureSize
; pos
--)
279 if (TestFinishSignatureCandidate(buffer
+ pos
- kSignatureSize
))
281 _position
+= pos
- startPos
;
282 return stream
->Seek(_position
, STREAM_SEEK_SET
, NULL
);
285 numPrevBytes
= kSignatureSize
- 1;
286 memmove(buffer
+ kBufferSize
- numPrevBytes
, buffer
+ startPos
+ 1, numPrevBytes
);
292 // S_FALSE means that file is not archive
293 HRESULT
CInArchive::Open(IInStream
*stream
, const UInt64
*searchHeaderSizeLimit
)
296 RINOK(stream
->Seek(0, STREAM_SEEK_CUR
, &_arhiveBeginStreamPosition
))
297 _position
= _arhiveBeginStreamPosition
;
299 HRESULT result
= FindFinishSignature(stream
, searchHeaderSizeLimit
);
301 _finishSignature
= true;
304 if (result
!= S_FALSE
)
306 _finishSignature
= false;
307 RINOK(FindAndReadSignature(stream
, searchHeaderSizeLimit
));
310 RINOK(FindAndReadSignature(stream
, searchHeaderSizeLimit
));
316 void CInArchive::Close()
321 HRESULT
CInArchive::SkeepData(UInt64 size
)
323 for (UInt64 i
= 0; i
< size
; i
++)
326 RINOK(ReadByte(temp
));
331 HRESULT
CInArchive::SkeepData()
334 RINOK(ReadNumber(size
));
335 return SkeepData(size
);
338 HRESULT
CInArchive::ReadArchiveProperties(CInArchiveInfo
&archiveInfo
)
344 if (type
== NID::kEnd
)
351 HRESULT
CInArchive::GetNextFolderItem(CFolder
&folder
)
354 RINOK(ReadNum(numCoders
));
356 folder
.Coders
.Clear();
357 folder
.Coders
.Reserve((int)numCoders
);
358 CNum numInStreams
= 0;
359 CNum numOutStreams
= 0;
361 for (i
= 0; i
< numCoders
; i
++)
363 folder
.Coders
.Add(CCoderInfo());
364 CCoderInfo
&coder
= folder
.Coders
.Back();
368 coder
.AltCoders
.Add(CAltCoderInfo());
369 CAltCoderInfo
&altCoder
= coder
.AltCoders
.Back();
371 RINOK(ReadByte(mainByte
));
372 altCoder
.MethodID
.IDSize
= mainByte
& 0xF;
373 RINOK(ReadBytes(altCoder
.MethodID
.ID
, altCoder
.MethodID
.IDSize
));
374 if ((mainByte
& 0x10) != 0)
376 RINOK(ReadNum(coder
.NumInStreams
));
377 RINOK(ReadNum(coder
.NumOutStreams
));
381 coder
.NumInStreams
= 1;
382 coder
.NumOutStreams
= 1;
384 if ((mainByte
& 0x20) != 0)
386 CNum propertiesSize
= 0;
387 RINOK(ReadNum(propertiesSize
));
388 altCoder
.Properties
.SetCapacity((size_t)propertiesSize
);
389 RINOK(ReadBytes((Byte
*)altCoder
.Properties
, (size_t)propertiesSize
));
391 if ((mainByte
& 0x80) == 0)
394 numInStreams
+= coder
.NumInStreams
;
395 numOutStreams
+= coder
.NumOutStreams
;
399 // RINOK(ReadNumber(numBindPairs));
400 numBindPairs
= numOutStreams
- 1;
401 folder
.BindPairs
.Clear();
402 folder
.BindPairs
.Reserve(numBindPairs
);
403 for (i
= 0; i
< numBindPairs
; i
++)
406 RINOK(ReadNum(bindPair
.InIndex
));
407 RINOK(ReadNum(bindPair
.OutIndex
));
408 folder
.BindPairs
.Add(bindPair
);
411 CNum numPackedStreams
= numInStreams
- numBindPairs
;
412 folder
.PackStreams
.Reserve(numPackedStreams
);
413 if (numPackedStreams
== 1)
415 for (CNum j
= 0; j
< numInStreams
; j
++)
416 if (folder
.FindBindPairForInStream(j
) < 0)
418 folder
.PackStreams
.Add(j
);
423 for(i
= 0; i
< numPackedStreams
; i
++)
426 RINOK(ReadNum(packStreamInfo
));
427 folder
.PackStreams
.Add(packStreamInfo
);
433 HRESULT
CInArchive::WaitAttribute(UInt64 attribute
)
439 if (type
== attribute
)
441 if (type
== NID::kEnd
)
447 HRESULT
CInArchive::ReadHashDigests(int numItems
,
448 CRecordVector
<bool> &digestsDefined
,
449 CRecordVector
<UInt32
> &digests
)
451 RINOK(ReadBoolVector2(numItems
, digestsDefined
));
453 digests
.Reserve(numItems
);
454 for(int i
= 0; i
< numItems
; i
++)
457 if (digestsDefined
[i
])
458 RINOK(ReadUInt32(crc
));
464 HRESULT
CInArchive::ReadPackInfo(
466 CRecordVector
<UInt64
> &packSizes
,
467 CRecordVector
<bool> &packCRCsDefined
,
468 CRecordVector
<UInt32
> &packCRCs
)
470 RINOK(ReadNumber(dataOffset
));
472 RINOK(ReadNum(numPackStreams
));
474 RINOK(WaitAttribute(NID::kSize
));
476 packSizes
.Reserve(numPackStreams
);
477 for(CNum i
= 0; i
< numPackStreams
; i
++)
480 RINOK(ReadNumber(size
));
488 if (type
== NID::kEnd
)
490 if (type
== NID::kCRC
)
492 RINOK(ReadHashDigests(numPackStreams
, packCRCsDefined
, packCRCs
));
497 if (packCRCsDefined
.IsEmpty())
499 packCRCsDefined
.Reserve(numPackStreams
);
500 packCRCsDefined
.Clear();
501 packCRCs
.Reserve(numPackStreams
);
503 for(CNum i
= 0; i
< numPackStreams
; i
++)
505 packCRCsDefined
.Add(false);
512 HRESULT
CInArchive::ReadUnPackInfo(
513 const CObjectVector
<CByteBuffer
> *dataVector
,
514 CObjectVector
<CFolder
> &folders
)
516 RINOK(WaitAttribute(NID::kFolder
));
518 RINOK(ReadNum(numFolders
));
521 CStreamSwitch streamSwitch
;
522 RINOK(streamSwitch
.Set(this, dataVector
));
524 folders
.Reserve((UInt32
)numFolders
);
525 for(CNum i
= 0; i
< numFolders
; i
++)
527 folders
.Add(CFolder());
528 RINOK(GetNextFolderItem(folders
.Back()));
532 RINOK(WaitAttribute(NID::kCodersUnPackSize
));
535 for(i
= 0; i
< numFolders
; i
++)
537 CFolder
&folder
= folders
[i
];
538 CNum numOutStreams
= folder
.GetNumOutStreams();
539 folder
.UnPackSizes
.Reserve(numOutStreams
);
540 for(CNum j
= 0; j
< numOutStreams
; j
++)
543 RINOK(ReadNumber(unPackSize
));
544 folder
.UnPackSizes
.Add(unPackSize
);
552 if (type
== NID::kEnd
)
554 if (type
== NID::kCRC
)
556 CRecordVector
<bool> crcsDefined
;
557 CRecordVector
<UInt32
> crcs
;
558 RINOK(ReadHashDigests(numFolders
, crcsDefined
, crcs
));
559 for(i
= 0; i
< numFolders
; i
++)
561 CFolder
&folder
= folders
[i
];
562 folder
.UnPackCRCDefined
= crcsDefined
[i
];
563 folder
.UnPackCRC
= crcs
[i
];
571 HRESULT
CInArchive::ReadSubStreamsInfo(
572 const CObjectVector
<CFolder
> &folders
,
573 CRecordVector
<CNum
> &numUnPackStreamsInFolders
,
574 CRecordVector
<UInt64
> &unPackSizes
,
575 CRecordVector
<bool> &digestsDefined
,
576 CRecordVector
<UInt32
> &digests
)
578 numUnPackStreamsInFolders
.Clear();
579 numUnPackStreamsInFolders
.Reserve(folders
.Size());
584 if (type
== NID::kNumUnPackStream
)
586 for(int i
= 0; i
< folders
.Size(); i
++)
589 RINOK(ReadNum(value
));
590 numUnPackStreamsInFolders
.Add(value
);
594 if (type
== NID::kCRC
|| type
== NID::kSize
)
596 if (type
== NID::kEnd
)
601 if (numUnPackStreamsInFolders
.IsEmpty())
602 for(int i
= 0; i
< folders
.Size(); i
++)
603 numUnPackStreamsInFolders
.Add(1);
606 for(i
= 0; i
< numUnPackStreamsInFolders
.Size(); i
++)
608 // v3.13 incorrectly worked with empty folders
609 // v4.07: we check that folder is empty
610 CNum numSubstreams
= numUnPackStreamsInFolders
[i
];
611 if (numSubstreams
== 0)
614 for (CNum j
= 1; j
< numSubstreams
; j
++)
617 if (type
== NID::kSize
)
619 RINOK(ReadNumber(size
));
620 unPackSizes
.Add(size
);
624 unPackSizes
.Add(folders
[i
].GetUnPackSize() - sum
);
626 if (type
== NID::kSize
)
632 int numDigestsTotal
= 0;
633 for(i
= 0; i
< folders
.Size(); i
++)
635 CNum numSubstreams
= numUnPackStreamsInFolders
[i
];
636 if (numSubstreams
!= 1 || !folders
[i
].UnPackCRCDefined
)
637 numDigests
+= numSubstreams
;
638 numDigestsTotal
+= numSubstreams
;
643 if (type
== NID::kCRC
)
645 CRecordVector
<bool> digestsDefined2
;
646 CRecordVector
<UInt32
> digests2
;
647 RINOK(ReadHashDigests(numDigests
, digestsDefined2
, digests2
));
649 for (i
= 0; i
< folders
.Size(); i
++)
651 CNum numSubstreams
= numUnPackStreamsInFolders
[i
];
652 const CFolder
&folder
= folders
[i
];
653 if (numSubstreams
== 1 && folder
.UnPackCRCDefined
)
655 digestsDefined
.Add(true);
656 digests
.Add(folder
.UnPackCRC
);
659 for (CNum j
= 0; j
< numSubstreams
; j
++, digestIndex
++)
661 digestsDefined
.Add(digestsDefined2
[digestIndex
]);
662 digests
.Add(digests2
[digestIndex
]);
666 else if (type
== NID::kEnd
)
668 if (digestsDefined
.IsEmpty())
670 digestsDefined
.Clear();
672 for (int i
= 0; i
< numDigestsTotal
; i
++)
674 digestsDefined
.Add(false);
688 HRESULT
CInArchive::ReadStreamsInfo(
689 const CObjectVector
<CByteBuffer
> *dataVector
,
691 CRecordVector
<UInt64
> &packSizes
,
692 CRecordVector
<bool> &packCRCsDefined
,
693 CRecordVector
<UInt32
> &packCRCs
,
694 CObjectVector
<CFolder
> &folders
,
695 CRecordVector
<CNum
> &numUnPackStreamsInFolders
,
696 CRecordVector
<UInt64
> &unPackSizes
,
697 CRecordVector
<bool> &digestsDefined
,
698 CRecordVector
<UInt32
> &digests
)
710 RINOK(ReadPackInfo(dataOffset
, packSizes
,
711 packCRCsDefined
, packCRCs
));
714 case NID::kUnPackInfo
:
716 RINOK(ReadUnPackInfo(dataVector
, folders
));
719 case NID::kSubStreamsInfo
:
721 RINOK(ReadSubStreamsInfo(folders
, numUnPackStreamsInFolders
,
722 unPackSizes
, digestsDefined
, digests
));
729 HRESULT
CInArchive::ReadFileNames(CObjectVector
<CFileItem
> &files
)
731 for(int i
= 0; i
< files
.Size(); i
++)
733 UString
&name
= files
[i
].Name
;
738 RINOK(ReadWideCharLE(c
));
747 HRESULT
CInArchive::ReadBoolVector(int numItems
, CBoolVector
&v
)
753 for(int i
= 0; i
< numItems
; i
++)
760 v
.Add((b
& mask
) != 0);
766 HRESULT
CInArchive::ReadBoolVector2(int numItems
, CBoolVector
&v
)
769 RINOK(ReadByte(allAreDefined
));
770 if (allAreDefined
== 0)
771 return ReadBoolVector(numItems
, v
);
774 for (int i
= 0; i
< numItems
; i
++)
779 HRESULT
CInArchive::ReadTime(const CObjectVector
<CByteBuffer
> &dataVector
,
780 CObjectVector
<CFileItem
> &files
, UInt64 type
)
782 CBoolVector boolVector
;
783 RINOK(ReadBoolVector2(files
.Size(), boolVector
))
785 CStreamSwitch streamSwitch
;
786 RINOK(streamSwitch
.Set(this, &dataVector
));
788 for(int i
= 0; i
< files
.Size(); i
++)
790 CFileItem
&file
= files
[i
];
791 CArchiveFileTime fileTime
;
792 bool defined
= boolVector
[i
];
796 RINOK(ReadUInt32(low
));
797 RINOK(ReadUInt32(high
));
798 fileTime
.dwLowDateTime
= low
;
799 fileTime
.dwHighDateTime
= high
;
803 case NID::kCreationTime
:
804 file
.IsCreationTimeDefined
= defined
;
806 file
.CreationTime
= fileTime
;
808 case NID::kLastWriteTime
:
809 file
.IsLastWriteTimeDefined
= defined
;
811 file
.LastWriteTime
= fileTime
;
813 case NID::kLastAccessTime
:
814 file
.IsLastAccessTimeDefined
= defined
;
816 file
.LastAccessTime
= fileTime
;
823 HRESULT
CInArchive::ReadAndDecodePackedStreams(UInt64 baseOffset
,
824 UInt64
&dataOffset
, CObjectVector
<CByteBuffer
> &dataVector
826 , ICryptoGetTextPassword
*getTextPassword
830 CRecordVector
<UInt64
> packSizes
;
831 CRecordVector
<bool> packCRCsDefined
;
832 CRecordVector
<UInt32
> packCRCs
;
833 CObjectVector
<CFolder
> folders
;
835 CRecordVector
<CNum
> numUnPackStreamsInFolders
;
836 CRecordVector
<UInt64
> unPackSizes
;
837 CRecordVector
<bool> digestsDefined
;
838 CRecordVector
<UInt32
> digests
;
840 RINOK(ReadStreamsInfo(NULL
,
846 numUnPackStreamsInFolders
,
851 // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
861 UInt64 dataStartPos
= baseOffset
+ dataOffset
;
862 for(int i
= 0; i
< folders
.Size(); i
++)
864 const CFolder
&folder
= folders
[i
];
865 dataVector
.Add(CByteBuffer());
866 CByteBuffer
&data
= dataVector
.Back();
867 UInt64 unPackSize
= folder
.GetUnPackSize();
868 if (unPackSize
> kNumMax
)
870 if (unPackSize
> 0xFFFFFFFF)
872 data
.SetCapacity((size_t)unPackSize
);
874 CSequentialOutStreamImp2
*outStreamSpec
= new CSequentialOutStreamImp2
;
875 CMyComPtr
<ISequentialOutStream
> outStream
= outStreamSpec
;
876 outStreamSpec
->Init(data
, (size_t)unPackSize
);
878 HRESULT result
= decoder
.Decode(_stream
, dataStartPos
,
879 &packSizes
[packIndex
], folder
, outStream
, NULL
889 if (folder
.UnPackCRCDefined
)
890 if (!CCRC::VerifyDigest(folder
.UnPackCRC
, data
, (UInt32
)unPackSize
))
891 throw CInArchiveException(CInArchiveException::kIncorrectHeader
);
892 for (int j
= 0; j
< folder
.PackStreams
.Size(); j
++)
893 dataStartPos
+= packSizes
[packIndex
++];
898 HRESULT
CInArchive::ReadHeader(CArchiveDatabaseEx
&database
900 , ICryptoGetTextPassword
*getTextPassword
907 if (type
== NID::kArchiveProperties
)
909 RINOK(ReadArchiveProperties(database
.ArchiveInfo
));
913 CObjectVector
<CByteBuffer
> dataVector
;
915 if (type
== NID::kAdditionalStreamsInfo
)
917 HRESULT result
= ReadAndDecodePackedStreams(
918 database
.ArchiveInfo
.StartPositionAfterHeader
,
919 database
.ArchiveInfo
.DataStartPosition2
,
926 database
.ArchiveInfo
.DataStartPosition2
+= database
.ArchiveInfo
.StartPositionAfterHeader
;
930 CRecordVector
<UInt64
> unPackSizes
;
931 CRecordVector
<bool> digestsDefined
;
932 CRecordVector
<UInt32
> digests
;
934 if (type
== NID::kMainStreamsInfo
)
936 RINOK(ReadStreamsInfo(&dataVector
,
937 database
.ArchiveInfo
.DataStartPosition
,
939 database
.PackCRCsDefined
,
942 database
.NumUnPackStreamsVector
,
946 database
.ArchiveInfo
.DataStartPosition
+= database
.ArchiveInfo
.StartPositionAfterHeader
;
951 for(int i
= 0; i
< database
.Folders
.Size(); i
++)
953 database
.NumUnPackStreamsVector
.Add(1);
954 CFolder
&folder
= database
.Folders
[i
];
955 unPackSizes
.Add(folder
.GetUnPackSize());
956 digestsDefined
.Add(folder
.UnPackCRCDefined
);
957 digests
.Add(folder
.UnPackCRC
);
961 database
.Files
.Clear();
963 if (type
== NID::kEnd
)
965 if (type
!= NID::kFilesInfo
)
966 throw CInArchiveException(CInArchiveException::kIncorrectHeader
);
969 RINOK(ReadNum(numFiles
));
970 database
.Files
.Reserve(numFiles
);
972 for(i
= 0; i
< numFiles
; i
++)
973 database
.Files
.Add(CFileItem());
975 database
.ArchiveInfo
.FileInfoPopIDs
.Add(NID::kSize
);
976 if (!database
.PackSizes
.IsEmpty())
977 database
.ArchiveInfo
.FileInfoPopIDs
.Add(NID::kPackInfo
);
978 if (numFiles
> 0 && !digests
.IsEmpty())
979 database
.ArchiveInfo
.FileInfoPopIDs
.Add(NID::kCRC
);
981 CBoolVector emptyStreamVector
;
982 emptyStreamVector
.Reserve((int)numFiles
);
983 for(i
= 0; i
< numFiles
; i
++)
984 emptyStreamVector
.Add(false);
985 CBoolVector emptyFileVector
;
986 CBoolVector antiFileVector
;
987 CNum numEmptyStreams
= 0;
989 // int sizePrev = -1;
996 if (sizePrev != _inByteBack->GetProcessedSize() - posPrev)
1000 RINOK(ReadID(type
));
1001 if (type
== NID::kEnd
)
1004 RINOK(ReadNumber(size
));
1007 // posPrev = _inByteBack->GetProcessedSize();
1009 database
.ArchiveInfo
.FileInfoPopIDs
.Add(type
);
1014 CStreamSwitch streamSwitch
;
1015 RINOK(streamSwitch
.Set(this, &dataVector
));
1016 RINOK(ReadFileNames(database
.Files
))
1019 case NID::kWinAttributes
:
1021 CBoolVector boolVector
;
1022 RINOK(ReadBoolVector2(database
.Files
.Size(), boolVector
))
1023 CStreamSwitch streamSwitch
;
1024 RINOK(streamSwitch
.Set(this, &dataVector
));
1025 for(i
= 0; i
< numFiles
; i
++)
1027 CFileItem
&file
= database
.Files
[i
];
1028 if (file
.AreAttributesDefined
= boolVector
[i
])
1030 RINOK(ReadUInt32(file
.Attributes
));
1035 case NID::kStartPos
:
1037 CBoolVector boolVector
;
1038 RINOK(ReadBoolVector2(database
.Files
.Size(), boolVector
))
1039 CStreamSwitch streamSwitch
;
1040 RINOK(streamSwitch
.Set(this, &dataVector
));
1041 for(i
= 0; i
< numFiles
; i
++)
1043 CFileItem
&file
= database
.Files
[i
];
1044 if (file
.IsStartPosDefined
= boolVector
[i
])
1046 RINOK(ReadUInt64(file
.StartPos
));
1051 case NID::kEmptyStream
:
1053 RINOK(ReadBoolVector(numFiles
, emptyStreamVector
))
1054 for (i
= 0; i
< (CNum
)emptyStreamVector
.Size(); i
++)
1055 if (emptyStreamVector
[i
])
1057 emptyFileVector
.Reserve(numEmptyStreams
);
1058 antiFileVector
.Reserve(numEmptyStreams
);
1059 for (i
= 0; i
< numEmptyStreams
; i
++)
1061 emptyFileVector
.Add(false);
1062 antiFileVector
.Add(false);
1066 case NID::kEmptyFile
:
1068 RINOK(ReadBoolVector(numEmptyStreams
, emptyFileVector
))
1073 RINOK(ReadBoolVector(numEmptyStreams
, antiFileVector
))
1076 case NID::kCreationTime
:
1077 case NID::kLastWriteTime
:
1078 case NID::kLastAccessTime
:
1080 RINOK(ReadTime(dataVector
, database
.Files
, type
))
1085 database
.ArchiveInfo
.FileInfoPopIDs
.DeleteBack();
1086 RINOK(SkeepData(size
));
1091 CNum emptyFileIndex
= 0;
1093 for(i
= 0; i
< numFiles
; i
++)
1095 CFileItem
&file
= database
.Files
[i
];
1096 file
.HasStream
= !emptyStreamVector
[i
];
1099 file
.IsDirectory
= false;
1100 file
.IsAnti
= false;
1101 file
.UnPackSize
= unPackSizes
[sizeIndex
];
1102 file
.FileCRC
= digests
[sizeIndex
];
1103 file
.IsFileCRCDefined
= digestsDefined
[sizeIndex
];
1108 file
.IsDirectory
= !emptyFileVector
[emptyFileIndex
];
1109 file
.IsAnti
= antiFileVector
[emptyFileIndex
];
1111 file
.UnPackSize
= 0;
1112 file
.IsFileCRCDefined
= false;
1119 void CArchiveDatabaseEx::FillFolderStartPackStream()
1121 FolderStartPackStreamIndex
.Clear();
1122 FolderStartPackStreamIndex
.Reserve(Folders
.Size());
1124 for(int i
= 0; i
< Folders
.Size(); i
++)
1126 FolderStartPackStreamIndex
.Add(startPos
);
1127 startPos
+= (CNum
)Folders
[i
].PackStreams
.Size();
1131 void CArchiveDatabaseEx::FillStartPos()
1133 PackStreamStartPositions
.Clear();
1134 PackStreamStartPositions
.Reserve(PackSizes
.Size());
1135 UInt64 startPos
= 0;
1136 for(int i
= 0; i
< PackSizes
.Size(); i
++)
1138 PackStreamStartPositions
.Add(startPos
);
1139 startPos
+= PackSizes
[i
];
1143 void CArchiveDatabaseEx::FillFolderStartFileIndex()
1145 FolderStartFileIndex
.Clear();
1146 FolderStartFileIndex
.Reserve(Folders
.Size());
1147 FileIndexToFolderIndexMap
.Clear();
1148 FileIndexToFolderIndexMap
.Reserve(Files
.Size());
1150 int folderIndex
= 0;
1151 CNum indexInFolder
= 0;
1152 for (int i
= 0; i
< Files
.Size(); i
++)
1154 const CFileItem
&file
= Files
[i
];
1155 bool emptyStream
= !file
.HasStream
;
1156 if (emptyStream
&& indexInFolder
== 0)
1158 FileIndexToFolderIndexMap
.Add(kNumNoIndex
);
1161 if (indexInFolder
== 0)
1163 // v3.13 incorrectly worked with empty folders
1164 // v4.07: Loop for skipping empty folders
1167 if (folderIndex
>= Folders
.Size())
1168 throw CInArchiveException(CInArchiveException::kIncorrectHeader
);
1169 FolderStartFileIndex
.Add(i
); // check it
1170 if (NumUnPackStreamsVector
[folderIndex
] != 0)
1175 FileIndexToFolderIndexMap
.Add(folderIndex
);
1179 if (indexInFolder
>= NumUnPackStreamsVector
[folderIndex
])
1187 HRESULT
CInArchive::ReadDatabase(CArchiveDatabaseEx
&database
1189 , ICryptoGetTextPassword
*getTextPassword
1194 database
.ArchiveInfo
.StartPosition
= _arhiveBeginStreamPosition
;
1197 RINOK(SafeReadDirect(&database
.ArchiveInfo
.Version
.Major
, 1));
1198 RINOK(SafeReadDirect(&database
.ArchiveInfo
.Version
.Minor
, 1));
1199 if (database
.ArchiveInfo
.Version
.Major
!= kMajorVersion
)
1200 throw CInArchiveException(CInArchiveException::kUnsupportedVersion
);
1203 if (_finishSignature
)
1205 RINOK(_stream
->Seek(_position
- (4 + kFinishHeaderSize
) -
1206 (kSignatureSize
+ 2), STREAM_SEEK_SET
, &_position
));
1210 UInt32 crcFromArchive
;
1211 RINOK(SafeReadDirectUInt32(crcFromArchive
));
1213 UInt64 nextHeaderOffset
;
1214 UInt64 nextHeaderSize
;
1215 UInt32 nextHeaderCRC
;
1217 RINOK(SafeReadDirectUInt64(nextHeaderOffset
));
1218 crc
.UpdateUInt64(nextHeaderOffset
);
1219 RINOK(SafeReadDirectUInt64(nextHeaderSize
));
1220 crc
.UpdateUInt64(nextHeaderSize
);
1221 RINOK(SafeReadDirectUInt32(nextHeaderCRC
));
1222 crc
.UpdateUInt32(nextHeaderCRC
);
1225 UInt64 archiveStartOffset
; // data offset from end if that struct
1226 UInt64 additionalStartBlockSize
; // start signature & start header size
1227 if (_finishSignature
)
1229 RINOK(SafeReadDirectUInt64(archiveStartOffset
));
1230 crc
.UpdateUInt64(archiveStartOffset
);
1231 RINOK(SafeReadDirectUInt64(additionalStartBlockSize
));
1232 crc
.UpdateUInt64(additionalStartBlockSize
);
1233 database
.ArchiveInfo
.StartPositionAfterHeader
= _position
+ archiveStartOffset
;
1238 database
.ArchiveInfo
.StartPositionAfterHeader
= _position
;
1240 if (crc
.GetDigest() != crcFromArchive
)
1241 throw CInArchiveException(CInArchiveException::kIncorrectHeader
);
1243 if (nextHeaderSize
== 0)
1246 if (nextHeaderSize
>= 0xFFFFFFFF)
1249 RINOK(_stream
->Seek(nextHeaderOffset
, STREAM_SEEK_CUR
, &_position
));
1251 CByteBuffer buffer2
;
1252 buffer2
.SetCapacity((size_t)nextHeaderSize
);
1253 RINOK(SafeReadDirect(buffer2
, (UInt32
)nextHeaderSize
));
1254 if (!CCRC::VerifyDigest(nextHeaderCRC
, buffer2
, (UInt32
)nextHeaderSize
))
1255 throw CInArchiveException(CInArchiveException::kIncorrectHeader
);
1257 CStreamSwitch streamSwitch
;
1258 streamSwitch
.Set(this, buffer2
);
1260 CObjectVector
<CByteBuffer
> dataVector
;
1265 RINOK(ReadID(type
));
1266 if (type
== NID::kHeader
)
1268 if (type
!= NID::kEncodedHeader
)
1269 throw CInArchiveException(CInArchiveException::kIncorrectHeader
);
1270 HRESULT result
= ReadAndDecodePackedStreams(
1271 database
.ArchiveInfo
.StartPositionAfterHeader
,
1272 database
.ArchiveInfo
.DataStartPosition2
,
1279 if (dataVector
.Size() == 0)
1281 if (dataVector
.Size() > 1)
1282 throw CInArchiveException(CInArchiveException::kIncorrectHeader
);
1283 streamSwitch
.Remove();
1284 streamSwitch
.Set(this, dataVector
.Front());
1287 return ReadHeader(database