Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / other-licenses / 7zstub / src / 7zip / Archive / 7z / 7zIn.cpp
blob86709d36d887d83f6498a51fc10328b1f96f6d70
1 // 7zIn.cpp
3 #include "StdAfx.h"
5 #include "7zIn.h"
6 #include "7zMethods.h"
7 #include "7zDecode.h"
8 #include "../../Common/StreamObjects.h"
9 #include "../../Common/StreamUtils.h"
10 #include "../../../Common/CRC.h"
12 namespace NArchive {
13 namespace N7z {
15 class CStreamSwitch
17 CInArchive *_archive;
18 bool _needRemove;
19 public:
20 CStreamSwitch(): _needRemove(false) {}
21 ~CStreamSwitch() { Remove(); }
22 void 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()
30 if (_needRemove)
32 _archive->DeleteByteStream();
33 _needRemove = false;
37 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
39 Remove();
40 _archive = archive;
41 _archive->AddByteStream(data, size);
42 _needRemove = true;
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)
52 Remove();
53 Byte external;
54 RINOK(archive->ReadByte(external));
55 if (external != 0)
57 CNum dataIndex;
58 RINOK(archive->ReadNum(dataIndex));
59 Set(archive, (*dataVector)[dataIndex]);
61 return S_OK;
65 CInArchiveException::CInArchiveException(CCauseType cause):
66 Cause(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;
77 return result;
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);
91 return S_OK;
94 HRESULT CInArchive::SafeReadDirectByte(Byte &b)
96 return SafeReadDirect(&b, 1);
99 HRESULT CInArchive::SafeReadDirectUInt32(UInt32 &value)
101 value = 0;
102 for (int i = 0; i < 4; i++)
104 Byte b;
105 RINOK(SafeReadDirectByte(b));
106 value |= (UInt32(b) << (8 * i));
108 return S_OK;
111 HRESULT CInArchive::SafeReadDirectUInt64(UInt64 &value)
113 value = 0;
114 for (int i = 0; i < 8; i++)
116 Byte b;
117 RINOK(SafeReadDirectByte(b));
118 value |= (UInt64(b) << (8 * i));
120 return S_OK;
123 HRESULT CInArchive::ReadNumber(UInt64 &value)
125 Byte firstByte;
126 RINOK(ReadByte(firstByte));
127 Byte mask = 0x80;
128 value = 0;
129 for (int i = 0; i < 8; i++)
131 if ((firstByte & mask) == 0)
133 UInt64 highPart = firstByte & (mask - 1);
134 value += (highPart << (i * 8));
135 return S_OK;
137 Byte b;
138 RINOK(ReadByte(b));
139 value |= (UInt64(b) << (8 * i));
140 mask >>= 1;
142 return S_OK;
145 HRESULT CInArchive::ReadNum(CNum &value)
147 UInt64 value64;
148 RINOK(ReadNumber(value64));
149 if (value64 > kNumMax)
150 return E_FAIL;
151 value = (CNum)value64;
152 return S_OK;
155 HRESULT CInArchive::ReadUInt32(UInt32 &value)
157 value = 0;
158 for (int i = 0; i < 4; i++)
160 Byte b;
161 RINOK(ReadByte(b));
162 value |= (UInt32(b) << (8 * i));
164 return S_OK;
167 HRESULT CInArchive::ReadUInt64(UInt64 &value)
169 value = 0;
170 for (int i = 0; i < 8; i++)
172 Byte b;
173 RINOK(ReadByte(b));
174 value |= (UInt64(b) << (8 * i));
176 return S_OK;
179 static inline bool TestSignatureCandidate(const void *testBytes)
181 for (int i = 0; i < kSignatureSize; i++)
182 if (((const Byte *)testBytes)[i] != kSignature[i])
183 return false;
184 return true;
187 #ifdef _7Z_VOL
188 static inline bool TestFinishSignatureCandidate(const void *testBytes)
190 for (int i = 0; i < kSignatureSize; i++)
191 if (((const Byte *)testBytes)[i] != kFinishSignature[i])
192 return false;
193 return true;
195 #endif
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)
206 return S_FALSE;
207 if (TestSignatureCandidate(signature))
208 return S_OK;
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;
217 while(true)
219 if (searchHeaderSizeLimit != NULL)
220 if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
221 return S_FALSE;
222 UInt32 numReadBytes = kBufferSize - numPrevBytes;
223 RINOK(ReadDirect(stream, buffer + numPrevBytes, numReadBytes, &processedSize));
224 UInt32 numBytesInBuffer = numPrevBytes + processedSize;
225 if (numBytesInBuffer < kSignatureSize)
226 return S_FALSE;
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
244 #ifdef _7Z_VOL
245 HRESULT CInArchive::FindFinishSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
247 RINOK(stream->Seek(0, STREAM_SEEK_END, &_position));
248 if (_position < kSignatureSize)
249 return S_FALSE;
251 CByteBuffer byteBuffer;
252 const UInt32 kBufferSize = (1 << 18);
253 byteBuffer.SetCapacity(kBufferSize);
254 Byte *buffer = byteBuffer;
255 UInt32 numPrevBytes = 0;
256 UInt64 limitPos = 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)
268 return S_FALSE;
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)
275 return S_FALSE;
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);
288 return S_FALSE;
290 #endif
292 // S_FALSE means that file is not archive
293 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
295 Close();
296 RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
297 _position = _arhiveBeginStreamPosition;
298 #ifdef _7Z_VOL
299 HRESULT result = FindFinishSignature(stream, searchHeaderSizeLimit);
300 if (result == S_OK)
301 _finishSignature = true;
302 else
304 if (result != S_FALSE)
305 return result;
306 _finishSignature = false;
307 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
309 #else
310 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
311 #endif
312 _stream = stream;
313 return S_OK;
316 void CInArchive::Close()
318 _stream.Release();
321 HRESULT CInArchive::SkeepData(UInt64 size)
323 for (UInt64 i = 0; i < size; i++)
325 Byte temp;
326 RINOK(ReadByte(temp));
328 return S_OK;
331 HRESULT CInArchive::SkeepData()
333 UInt64 size;
334 RINOK(ReadNumber(size));
335 return SkeepData(size);
338 HRESULT CInArchive::ReadArchiveProperties(CInArchiveInfo &archiveInfo)
340 while(true)
342 UInt64 type;
343 RINOK(ReadID(type));
344 if (type == NID::kEnd)
345 break;
346 SkeepData();
348 return S_OK;
351 HRESULT CInArchive::GetNextFolderItem(CFolder &folder)
353 CNum numCoders;
354 RINOK(ReadNum(numCoders));
356 folder.Coders.Clear();
357 folder.Coders.Reserve((int)numCoders);
358 CNum numInStreams = 0;
359 CNum numOutStreams = 0;
360 CNum i;
361 for (i = 0; i < numCoders; i++)
363 folder.Coders.Add(CCoderInfo());
364 CCoderInfo &coder = folder.Coders.Back();
366 while (true)
368 coder.AltCoders.Add(CAltCoderInfo());
369 CAltCoderInfo &altCoder = coder.AltCoders.Back();
370 Byte mainByte;
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));
379 else
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)
392 break;
394 numInStreams += coder.NumInStreams;
395 numOutStreams += coder.NumOutStreams;
398 CNum numBindPairs;
399 // RINOK(ReadNumber(numBindPairs));
400 numBindPairs = numOutStreams - 1;
401 folder.BindPairs.Clear();
402 folder.BindPairs.Reserve(numBindPairs);
403 for (i = 0; i < numBindPairs; i++)
405 CBindPair bindPair;
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);
419 break;
422 else
423 for(i = 0; i < numPackedStreams; i++)
425 CNum packStreamInfo;
426 RINOK(ReadNum(packStreamInfo));
427 folder.PackStreams.Add(packStreamInfo);
430 return S_OK;
433 HRESULT CInArchive::WaitAttribute(UInt64 attribute)
435 while(true)
437 UInt64 type;
438 RINOK(ReadID(type));
439 if (type == attribute)
440 return S_OK;
441 if (type == NID::kEnd)
442 return S_FALSE;
443 RINOK(SkeepData());
447 HRESULT CInArchive::ReadHashDigests(int numItems,
448 CRecordVector<bool> &digestsDefined,
449 CRecordVector<UInt32> &digests)
451 RINOK(ReadBoolVector2(numItems, digestsDefined));
452 digests.Clear();
453 digests.Reserve(numItems);
454 for(int i = 0; i < numItems; i++)
456 UInt32 crc;
457 if (digestsDefined[i])
458 RINOK(ReadUInt32(crc));
459 digests.Add(crc);
461 return S_OK;
464 HRESULT CInArchive::ReadPackInfo(
465 UInt64 &dataOffset,
466 CRecordVector<UInt64> &packSizes,
467 CRecordVector<bool> &packCRCsDefined,
468 CRecordVector<UInt32> &packCRCs)
470 RINOK(ReadNumber(dataOffset));
471 CNum numPackStreams;
472 RINOK(ReadNum(numPackStreams));
474 RINOK(WaitAttribute(NID::kSize));
475 packSizes.Clear();
476 packSizes.Reserve(numPackStreams);
477 for(CNum i = 0; i < numPackStreams; i++)
479 UInt64 size;
480 RINOK(ReadNumber(size));
481 packSizes.Add(size);
484 UInt64 type;
485 while(true)
487 RINOK(ReadID(type));
488 if (type == NID::kEnd)
489 break;
490 if (type == NID::kCRC)
492 RINOK(ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs));
493 continue;
495 RINOK(SkeepData());
497 if (packCRCsDefined.IsEmpty())
499 packCRCsDefined.Reserve(numPackStreams);
500 packCRCsDefined.Clear();
501 packCRCs.Reserve(numPackStreams);
502 packCRCs.Clear();
503 for(CNum i = 0; i < numPackStreams; i++)
505 packCRCsDefined.Add(false);
506 packCRCs.Add(0);
509 return S_OK;
512 HRESULT CInArchive::ReadUnPackInfo(
513 const CObjectVector<CByteBuffer> *dataVector,
514 CObjectVector<CFolder> &folders)
516 RINOK(WaitAttribute(NID::kFolder));
517 CNum numFolders;
518 RINOK(ReadNum(numFolders));
521 CStreamSwitch streamSwitch;
522 RINOK(streamSwitch.Set(this, dataVector));
523 folders.Clear();
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));
534 CNum i;
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++)
542 UInt64 unPackSize;
543 RINOK(ReadNumber(unPackSize));
544 folder.UnPackSizes.Add(unPackSize);
548 while(true)
550 UInt64 type;
551 RINOK(ReadID(type));
552 if (type == NID::kEnd)
553 return S_OK;
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];
565 continue;
567 RINOK(SkeepData());
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());
580 UInt64 type;
581 while(true)
583 RINOK(ReadID(type));
584 if (type == NID::kNumUnPackStream)
586 for(int i = 0; i < folders.Size(); i++)
588 CNum value;
589 RINOK(ReadNum(value));
590 numUnPackStreamsInFolders.Add(value);
592 continue;
594 if (type == NID::kCRC || type == NID::kSize)
595 break;
596 if (type == NID::kEnd)
597 break;
598 RINOK(SkeepData());
601 if (numUnPackStreamsInFolders.IsEmpty())
602 for(int i = 0; i < folders.Size(); i++)
603 numUnPackStreamsInFolders.Add(1);
605 int i;
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)
612 continue;
613 UInt64 sum = 0;
614 for (CNum j = 1; j < numSubstreams; j++)
616 UInt64 size;
617 if (type == NID::kSize)
619 RINOK(ReadNumber(size));
620 unPackSizes.Add(size);
621 sum += size;
624 unPackSizes.Add(folders[i].GetUnPackSize() - sum);
626 if (type == NID::kSize)
628 RINOK(ReadID(type));
631 int numDigests = 0;
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;
641 while(true)
643 if (type == NID::kCRC)
645 CRecordVector<bool> digestsDefined2;
646 CRecordVector<UInt32> digests2;
647 RINOK(ReadHashDigests(numDigests, digestsDefined2, digests2));
648 int digestIndex = 0;
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);
658 else
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();
671 digests.Clear();
672 for (int i = 0; i < numDigestsTotal; i++)
674 digestsDefined.Add(false);
675 digests.Add(0);
678 return S_OK;
680 else
682 RINOK(SkeepData());
684 RINOK(ReadID(type));
688 HRESULT CInArchive::ReadStreamsInfo(
689 const CObjectVector<CByteBuffer> *dataVector,
690 UInt64 &dataOffset,
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)
700 while(true)
702 UInt64 type;
703 RINOK(ReadID(type));
704 switch(type)
706 case NID::kEnd:
707 return S_OK;
708 case NID::kPackInfo:
710 RINOK(ReadPackInfo(dataOffset, packSizes,
711 packCRCsDefined, packCRCs));
712 break;
714 case NID::kUnPackInfo:
716 RINOK(ReadUnPackInfo(dataVector, folders));
717 break;
719 case NID::kSubStreamsInfo:
721 RINOK(ReadSubStreamsInfo(folders, numUnPackStreamsInFolders,
722 unPackSizes, digestsDefined, digests));
723 break;
729 HRESULT CInArchive::ReadFileNames(CObjectVector<CFileItem> &files)
731 for(int i = 0; i < files.Size(); i++)
733 UString &name = files[i].Name;
734 name.Empty();
735 while (true)
737 wchar_t c;
738 RINOK(ReadWideCharLE(c));
739 if (c == L'\0')
740 break;
741 name += c;
744 return S_OK;
747 HRESULT CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
749 v.Clear();
750 v.Reserve(numItems);
751 Byte b;
752 Byte mask = 0;
753 for(int i = 0; i < numItems; i++)
755 if (mask == 0)
757 RINOK(ReadByte(b));
758 mask = 0x80;
760 v.Add((b & mask) != 0);
761 mask >>= 1;
763 return S_OK;
766 HRESULT CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
768 Byte allAreDefined;
769 RINOK(ReadByte(allAreDefined));
770 if (allAreDefined == 0)
771 return ReadBoolVector(numItems, v);
772 v.Clear();
773 v.Reserve(numItems);
774 for (int i = 0; i < numItems; i++)
775 v.Add(true);
776 return S_OK;
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];
793 if (defined)
795 UInt32 low, high;
796 RINOK(ReadUInt32(low));
797 RINOK(ReadUInt32(high));
798 fileTime.dwLowDateTime = low;
799 fileTime.dwHighDateTime = high;
801 switch(type)
803 case NID::kCreationTime:
804 file.IsCreationTimeDefined = defined;
805 if (defined)
806 file.CreationTime = fileTime;
807 break;
808 case NID::kLastWriteTime:
809 file.IsLastWriteTimeDefined = defined;
810 if (defined)
811 file.LastWriteTime = fileTime;
812 break;
813 case NID::kLastAccessTime:
814 file.IsLastAccessTimeDefined = defined;
815 if (defined)
816 file.LastAccessTime = fileTime;
817 break;
820 return S_OK;
823 HRESULT CInArchive::ReadAndDecodePackedStreams(UInt64 baseOffset,
824 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
825 #ifndef _NO_CRYPTO
826 , ICryptoGetTextPassword *getTextPassword
827 #endif
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,
841 dataOffset,
842 packSizes,
843 packCRCsDefined,
844 packCRCs,
845 folders,
846 numUnPackStreamsInFolders,
847 unPackSizes,
848 digestsDefined,
849 digests));
851 // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
853 CNum packIndex = 0;
854 CDecoder decoder(
855 #ifdef _ST_MODE
856 false
857 #else
858 true
859 #endif
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)
869 return E_FAIL;
870 if (unPackSize > 0xFFFFFFFF)
871 return E_FAIL;
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
880 #ifndef _NO_CRYPTO
881 , getTextPassword
882 #endif
883 #ifdef COMPRESS_MT
884 , false, 1
885 #endif
887 RINOK(result);
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++];
895 return S_OK;
898 HRESULT CInArchive::ReadHeader(CArchiveDatabaseEx &database
899 #ifndef _NO_CRYPTO
900 , ICryptoGetTextPassword *getTextPassword
901 #endif
904 UInt64 type;
905 RINOK(ReadID(type));
907 if (type == NID::kArchiveProperties)
909 RINOK(ReadArchiveProperties(database.ArchiveInfo));
910 RINOK(ReadID(type));
913 CObjectVector<CByteBuffer> dataVector;
915 if (type == NID::kAdditionalStreamsInfo)
917 HRESULT result = ReadAndDecodePackedStreams(
918 database.ArchiveInfo.StartPositionAfterHeader,
919 database.ArchiveInfo.DataStartPosition2,
920 dataVector
921 #ifndef _NO_CRYPTO
922 , getTextPassword
923 #endif
925 RINOK(result);
926 database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader;
927 RINOK(ReadID(type));
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,
938 database.PackSizes,
939 database.PackCRCsDefined,
940 database.PackCRCs,
941 database.Folders,
942 database.NumUnPackStreamsVector,
943 unPackSizes,
944 digestsDefined,
945 digests));
946 database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader;
947 RINOK(ReadID(type));
949 else
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)
964 return S_OK;
965 if (type != NID::kFilesInfo)
966 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
968 CNum numFiles;
969 RINOK(ReadNum(numFiles));
970 database.Files.Reserve(numFiles);
971 CNum i;
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;
990 // int posPrev = 0;
992 while(true)
995 if (sizePrev >= 0)
996 if (sizePrev != _inByteBack->GetProcessedSize() - posPrev)
997 throw 2;
999 UInt64 type;
1000 RINOK(ReadID(type));
1001 if (type == NID::kEnd)
1002 break;
1003 UInt64 size;
1004 RINOK(ReadNumber(size));
1006 // sizePrev = size;
1007 // posPrev = _inByteBack->GetProcessedSize();
1009 database.ArchiveInfo.FileInfoPopIDs.Add(type);
1010 switch(type)
1012 case NID::kName:
1014 CStreamSwitch streamSwitch;
1015 RINOK(streamSwitch.Set(this, &dataVector));
1016 RINOK(ReadFileNames(database.Files))
1017 break;
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));
1033 break;
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));
1049 break;
1051 case NID::kEmptyStream:
1053 RINOK(ReadBoolVector(numFiles, emptyStreamVector))
1054 for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
1055 if (emptyStreamVector[i])
1056 numEmptyStreams++;
1057 emptyFileVector.Reserve(numEmptyStreams);
1058 antiFileVector.Reserve(numEmptyStreams);
1059 for (i = 0; i < numEmptyStreams; i++)
1061 emptyFileVector.Add(false);
1062 antiFileVector.Add(false);
1064 break;
1066 case NID::kEmptyFile:
1068 RINOK(ReadBoolVector(numEmptyStreams, emptyFileVector))
1069 break;
1071 case NID::kAnti:
1073 RINOK(ReadBoolVector(numEmptyStreams, antiFileVector))
1074 break;
1076 case NID::kCreationTime:
1077 case NID::kLastWriteTime:
1078 case NID::kLastAccessTime:
1080 RINOK(ReadTime(dataVector, database.Files, type))
1081 break;
1083 default:
1085 database.ArchiveInfo.FileInfoPopIDs.DeleteBack();
1086 RINOK(SkeepData(size));
1091 CNum emptyFileIndex = 0;
1092 CNum sizeIndex = 0;
1093 for(i = 0; i < numFiles; i++)
1095 CFileItem &file = database.Files[i];
1096 file.HasStream = !emptyStreamVector[i];
1097 if(file.HasStream)
1099 file.IsDirectory = false;
1100 file.IsAnti = false;
1101 file.UnPackSize = unPackSizes[sizeIndex];
1102 file.FileCRC = digests[sizeIndex];
1103 file.IsFileCRCDefined = digestsDefined[sizeIndex];
1104 sizeIndex++;
1106 else
1108 file.IsDirectory = !emptyFileVector[emptyFileIndex];
1109 file.IsAnti = antiFileVector[emptyFileIndex];
1110 emptyFileIndex++;
1111 file.UnPackSize = 0;
1112 file.IsFileCRCDefined = false;
1115 return S_OK;
1119 void CArchiveDatabaseEx::FillFolderStartPackStream()
1121 FolderStartPackStreamIndex.Clear();
1122 FolderStartPackStreamIndex.Reserve(Folders.Size());
1123 CNum startPos = 0;
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);
1159 continue;
1161 if (indexInFolder == 0)
1163 // v3.13 incorrectly worked with empty folders
1164 // v4.07: Loop for skipping empty folders
1165 while(true)
1167 if (folderIndex >= Folders.Size())
1168 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
1169 FolderStartFileIndex.Add(i); // check it
1170 if (NumUnPackStreamsVector[folderIndex] != 0)
1171 break;
1172 folderIndex++;
1175 FileIndexToFolderIndexMap.Add(folderIndex);
1176 if (emptyStream)
1177 continue;
1178 indexInFolder++;
1179 if (indexInFolder >= NumUnPackStreamsVector[folderIndex])
1181 folderIndex++;
1182 indexInFolder = 0;
1187 HRESULT CInArchive::ReadDatabase(CArchiveDatabaseEx &database
1188 #ifndef _NO_CRYPTO
1189 , ICryptoGetTextPassword *getTextPassword
1190 #endif
1193 database.Clear();
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);
1202 #ifdef _7Z_VOL
1203 if (_finishSignature)
1205 RINOK(_stream->Seek(_position - (4 + kFinishHeaderSize) -
1206 (kSignatureSize + 2), STREAM_SEEK_SET, &_position));
1208 #endif
1210 UInt32 crcFromArchive;
1211 RINOK(SafeReadDirectUInt32(crcFromArchive));
1213 UInt64 nextHeaderOffset;
1214 UInt64 nextHeaderSize;
1215 UInt32 nextHeaderCRC;
1216 CCRC crc;
1217 RINOK(SafeReadDirectUInt64(nextHeaderOffset));
1218 crc.UpdateUInt64(nextHeaderOffset);
1219 RINOK(SafeReadDirectUInt64(nextHeaderSize));
1220 crc.UpdateUInt64(nextHeaderSize);
1221 RINOK(SafeReadDirectUInt32(nextHeaderCRC));
1222 crc.UpdateUInt32(nextHeaderCRC);
1224 #ifdef _7Z_VOL
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;
1235 else
1236 #endif
1238 database.ArchiveInfo.StartPositionAfterHeader = _position;
1240 if (crc.GetDigest() != crcFromArchive)
1241 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
1243 if (nextHeaderSize == 0)
1244 return S_OK;
1246 if (nextHeaderSize >= 0xFFFFFFFF)
1247 return E_FAIL;
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;
1262 while (true)
1264 UInt64 type;
1265 RINOK(ReadID(type));
1266 if (type == NID::kHeader)
1267 break;
1268 if (type != NID::kEncodedHeader)
1269 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
1270 HRESULT result = ReadAndDecodePackedStreams(
1271 database.ArchiveInfo.StartPositionAfterHeader,
1272 database.ArchiveInfo.DataStartPosition2,
1273 dataVector
1274 #ifndef _NO_CRYPTO
1275 , getTextPassword
1276 #endif
1278 RINOK(result);
1279 if (dataVector.Size() == 0)
1280 return S_OK;
1281 if (dataVector.Size() > 1)
1282 throw CInArchiveException(CInArchiveException::kIncorrectHeader);
1283 streamSwitch.Remove();
1284 streamSwitch.Set(this, dataVector.Front());
1287 return ReadHeader(database
1288 #ifndef _NO_CRYPTO
1289 , getTextPassword
1290 #endif