view src/win32/7zip/7z/CPP/7zip/Archive/7z/7zIn.cpp @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line source
1 // 7zIn.cpp
3 #include "StdAfx.h"
5 extern "C"
6 {
7 #include "../../../../C/7zCrc.h"
8 #include "../../../../C/CpuArch.h"
9 }
11 #include "../../Common/StreamObjects.h"
12 #include "../../Common/StreamUtils.h"
14 #include "7zDecode.h"
15 #include "7zIn.h"
17 #define Get16(p) GetUi16(p)
18 #define Get32(p) GetUi32(p)
19 #define Get64(p) GetUi64(p)
21 // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader
22 #ifndef _SFX
23 #define FORMAT_7Z_RECOVERY
24 #endif
26 namespace NArchive {
27 namespace N7z {
29 static void BoolVector_Fill_False(CBoolVector &v, int size)
30 {
31 v.Clear();
32 v.Reserve(size);
33 for (int i = 0; i < size; i++)
34 v.Add(false);
35 }
37 static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index)
38 {
39 if (index >= (UInt32)v.Size())
40 return true;
41 bool res = v[index];
42 v[index] = true;
43 return res;
44 }
46 bool CFolder::CheckStructure() const
47 {
48 const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it
49 const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax
50 const int kNumBindsMax = 32;
52 if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax)
53 return false;
55 {
56 CBoolVector v;
57 BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size());
59 int i;
60 for (i = 0; i < BindPairs.Size(); i++)
61 if (BoolVector_GetAndSet(v, BindPairs[i].InIndex))
62 return false;
63 for (i = 0; i < PackStreams.Size(); i++)
64 if (BoolVector_GetAndSet(v, PackStreams[i]))
65 return false;
67 BoolVector_Fill_False(v, UnpackSizes.Size());
68 for (i = 0; i < BindPairs.Size(); i++)
69 if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex))
70 return false;
71 }
73 UInt32 mask[kMaskSize];
74 int i;
75 for (i = 0; i < kMaskSize; i++)
76 mask[i] = 0;
78 {
79 CIntVector inStreamToCoder, outStreamToCoder;
80 for (i = 0; i < Coders.Size(); i++)
81 {
82 CNum j;
83 const CCoderInfo &coder = Coders[i];
84 for (j = 0; j < coder.NumInStreams; j++)
85 inStreamToCoder.Add(i);
86 for (j = 0; j < coder.NumOutStreams; j++)
87 outStreamToCoder.Add(i);
88 }
90 for (i = 0; i < BindPairs.Size(); i++)
91 {
92 const CBindPair &bp = BindPairs[i];
93 mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]);
94 }
95 }
97 for (i = 0; i < kMaskSize; i++)
98 for (int j = 0; j < kMaskSize; j++)
99 if (((1 << j) & mask[i]) != 0)
100 mask[i] |= mask[j];
102 for (i = 0; i < kMaskSize; i++)
103 if (((1 << i) & mask[i]) != 0)
104 return false;
106 return true;
107 }
109 class CInArchiveException {};
111 static void ThrowException() { throw CInArchiveException(); }
112 static inline void ThrowEndOfData() { ThrowException(); }
113 static inline void ThrowUnsupported() { ThrowException(); }
114 static inline void ThrowIncorrect() { ThrowException(); }
115 static inline void ThrowUnsupportedVersion() { ThrowException(); }
117 /*
118 class CInArchiveException
119 {
120 public:
121 enum CCauseType
122 {
123 kUnsupportedVersion = 0,
124 kUnsupported,
125 kIncorrect,
126 kEndOfData,
127 } Cause;
128 CInArchiveException(CCauseType cause): Cause(cause) {};
129 };
131 static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
132 static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); }
133 static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
134 static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); }
135 static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
136 */
138 class CStreamSwitch
139 {
140 CInArchive *_archive;
141 bool _needRemove;
142 public:
143 CStreamSwitch(): _needRemove(false) {}
144 ~CStreamSwitch() { Remove(); }
145 void Remove();
146 void Set(CInArchive *archive, const Byte *data, size_t size);
147 void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
148 void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
149 };
151 void CStreamSwitch::Remove()
152 {
153 if (_needRemove)
154 {
155 _archive->DeleteByteStream();
156 _needRemove = false;
157 }
158 }
160 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
161 {
162 Remove();
163 _archive = archive;
164 _archive->AddByteStream(data, size);
165 _needRemove = true;
166 }
168 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
169 {
170 Set(archive, byteBuffer, byteBuffer.GetCapacity());
171 }
173 void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
174 {
175 Remove();
176 Byte external = archive->ReadByte();
177 if (external != 0)
178 {
179 int dataIndex = (int)archive->ReadNum();
180 if (dataIndex < 0 || dataIndex >= dataVector->Size())
181 ThrowIncorrect();
182 Set(archive, (*dataVector)[dataIndex]);
183 }
184 }
186 Byte CInByte2::ReadByte()
187 {
188 if (_pos >= _size)
189 ThrowEndOfData();
190 return _buffer[_pos++];
191 }
193 void CInByte2::ReadBytes(Byte *data, size_t size)
194 {
195 if (size > _size - _pos)
196 ThrowEndOfData();
197 for (size_t i = 0; i < size; i++)
198 data[i] = _buffer[_pos++];
199 }
201 void CInByte2::SkeepData(UInt64 size)
202 {
203 if (size > _size - _pos)
204 ThrowEndOfData();
205 _pos += (size_t)size;
206 }
208 void CInByte2::SkeepData()
209 {
210 SkeepData(ReadNumber());
211 }
213 UInt64 CInByte2::ReadNumber()
214 {
215 if (_pos >= _size)
216 ThrowEndOfData();
217 Byte firstByte = _buffer[_pos++];
218 Byte mask = 0x80;
219 UInt64 value = 0;
220 for (int i = 0; i < 8; i++)
221 {
222 if ((firstByte & mask) == 0)
223 {
224 UInt64 highPart = firstByte & (mask - 1);
225 value += (highPart << (i * 8));
226 return value;
227 }
228 if (_pos >= _size)
229 ThrowEndOfData();
230 value |= ((UInt64)_buffer[_pos++] << (8 * i));
231 mask >>= 1;
232 }
233 return value;
234 }
236 CNum CInByte2::ReadNum()
237 {
238 UInt64 value = ReadNumber();
239 if (value > kNumMax)
240 ThrowUnsupported();
241 return (CNum)value;
242 }
244 UInt32 CInByte2::ReadUInt32()
245 {
246 if (_pos + 4 > _size)
247 ThrowEndOfData();
248 UInt32 res = Get32(_buffer + _pos);
249 _pos += 4;
250 return res;
251 }
253 UInt64 CInByte2::ReadUInt64()
254 {
255 if (_pos + 8 > _size)
256 ThrowEndOfData();
257 UInt64 res = Get64(_buffer + _pos);
258 _pos += 8;
259 return res;
260 }
262 void CInByte2::ReadString(UString &s)
263 {
264 const Byte *buf = _buffer + _pos;
265 size_t rem = (_size - _pos) / 2 * 2;
266 {
267 size_t i;
268 for (i = 0; i < rem; i += 2)
269 if (buf[i] == 0 && buf[i + 1] == 0)
270 break;
271 if (i == rem)
272 ThrowEndOfData();
273 rem = i;
274 }
275 int len = (int)(rem / 2);
276 if (len < 0 || (size_t)len * 2 != rem)
277 ThrowUnsupported();
278 wchar_t *p = s.GetBuffer(len);
279 int i;
280 for (i = 0; i < len; i++, buf += 2)
281 p[i] = (wchar_t)Get16(buf);
282 s.ReleaseBuffer(len);
283 _pos += rem + 2;
284 }
286 static inline bool TestSignatureCandidate(const Byte *p)
287 {
288 for (int i = 0; i < kSignatureSize; i++)
289 if (p[i] != kSignature[i])
290 return false;
291 return (p[0x1A] == 0 && p[0x1B] == 0);
292 }
294 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
295 {
296 RINOK(ReadStream_FALSE(stream, _header, kHeaderSize));
298 if (TestSignatureCandidate(_header))
299 return S_OK;
301 CByteBuffer byteBuffer;
302 const UInt32 kBufferSize = (1 << 16);
303 byteBuffer.SetCapacity(kBufferSize);
304 Byte *buffer = byteBuffer;
305 UInt32 numPrevBytes = kHeaderSize - 1;
306 memcpy(buffer, _header + 1, numPrevBytes);
307 UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
308 for (;;)
309 {
310 if (searchHeaderSizeLimit != NULL)
311 if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
312 break;
313 do
314 {
315 UInt32 numReadBytes = kBufferSize - numPrevBytes;
316 UInt32 processedSize;
317 RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
318 numPrevBytes += processedSize;
319 if (processedSize == 0)
320 return S_FALSE;
321 }
322 while (numPrevBytes < kHeaderSize);
323 UInt32 numTests = numPrevBytes - kHeaderSize + 1;
324 for (UInt32 pos = 0; pos < numTests; pos++)
325 {
326 for (; buffer[pos] != '7' && pos < numTests; pos++);
327 if (pos == numTests)
328 break;
329 if (TestSignatureCandidate(buffer + pos))
330 {
331 memcpy(_header, buffer + pos, kHeaderSize);
332 curTestPos += pos;
333 _arhiveBeginStreamPosition = curTestPos;
334 return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
335 }
336 }
337 curTestPos += numTests;
338 numPrevBytes -= numTests;
339 memmove(buffer, buffer + numTests, numPrevBytes);
340 }
341 return S_FALSE;
342 }
344 // S_FALSE means that file is not archive
345 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
346 {
347 HeadersSize = 0;
348 Close();
349 RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
350 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
351 _stream = stream;
352 return S_OK;
353 }
355 void CInArchive::Close()
356 {
357 _stream.Release();
358 }
360 void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
361 {
362 for (;;)
363 {
364 if (ReadID() == NID::kEnd)
365 break;
366 SkeepData();
367 }
368 }
370 void CInArchive::GetNextFolderItem(CFolder &folder)
371 {
372 CNum numCoders = ReadNum();
374 folder.Coders.Clear();
375 folder.Coders.Reserve((int)numCoders);
376 CNum numInStreams = 0;
377 CNum numOutStreams = 0;
378 CNum i;
379 for (i = 0; i < numCoders; i++)
380 {
381 folder.Coders.Add(CCoderInfo());
382 CCoderInfo &coder = folder.Coders.Back();
384 {
385 Byte mainByte = ReadByte();
386 int idSize = (mainByte & 0xF);
387 Byte longID[15];
388 ReadBytes(longID, idSize);
389 if (idSize > 8)
390 ThrowUnsupported();
391 UInt64 id = 0;
392 for (int j = 0; j < idSize; j++)
393 id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
394 coder.MethodID = id;
396 if ((mainByte & 0x10) != 0)
397 {
398 coder.NumInStreams = ReadNum();
399 coder.NumOutStreams = ReadNum();
400 }
401 else
402 {
403 coder.NumInStreams = 1;
404 coder.NumOutStreams = 1;
405 }
406 if ((mainByte & 0x20) != 0)
407 {
408 CNum propsSize = ReadNum();
409 coder.Props.SetCapacity((size_t)propsSize);
410 ReadBytes((Byte *)coder.Props, (size_t)propsSize);
411 }
412 if ((mainByte & 0x80) != 0)
413 ThrowUnsupported();
414 }
415 numInStreams += coder.NumInStreams;
416 numOutStreams += coder.NumOutStreams;
417 }
419 CNum numBindPairs = numOutStreams - 1;
420 folder.BindPairs.Clear();
421 folder.BindPairs.Reserve(numBindPairs);
422 for (i = 0; i < numBindPairs; i++)
423 {
424 CBindPair bp;
425 bp.InIndex = ReadNum();
426 bp.OutIndex = ReadNum();
427 folder.BindPairs.Add(bp);
428 }
430 if (numInStreams < numBindPairs)
431 ThrowUnsupported();
432 CNum numPackStreams = numInStreams - numBindPairs;
433 folder.PackStreams.Reserve(numPackStreams);
434 if (numPackStreams == 1)
435 {
436 for (i = 0; i < numInStreams; i++)
437 if (folder.FindBindPairForInStream(i) < 0)
438 {
439 folder.PackStreams.Add(i);
440 break;
441 }
442 if (folder.PackStreams.Size() != 1)
443 ThrowUnsupported();
444 }
445 else
446 for (i = 0; i < numPackStreams; i++)
447 folder.PackStreams.Add(ReadNum());
448 }
450 void CInArchive::WaitAttribute(UInt64 attribute)
451 {
452 for (;;)
453 {
454 UInt64 type = ReadID();
455 if (type == attribute)
456 return;
457 if (type == NID::kEnd)
458 ThrowIncorrect();
459 SkeepData();
460 }
461 }
463 void CInArchive::ReadHashDigests(int numItems,
464 CBoolVector &digestsDefined,
465 CRecordVector<UInt32> &digests)
466 {
467 ReadBoolVector2(numItems, digestsDefined);
468 digests.Clear();
469 digests.Reserve(numItems);
470 for (int i = 0; i < numItems; i++)
471 {
472 UInt32 crc = 0;
473 if (digestsDefined[i])
474 crc = ReadUInt32();
475 digests.Add(crc);
476 }
477 }
479 void CInArchive::ReadPackInfo(
480 UInt64 &dataOffset,
481 CRecordVector<UInt64> &packSizes,
482 CBoolVector &packCRCsDefined,
483 CRecordVector<UInt32> &packCRCs)
484 {
485 dataOffset = ReadNumber();
486 CNum numPackStreams = ReadNum();
488 WaitAttribute(NID::kSize);
489 packSizes.Clear();
490 packSizes.Reserve(numPackStreams);
491 for (CNum i = 0; i < numPackStreams; i++)
492 packSizes.Add(ReadNumber());
494 UInt64 type;
495 for (;;)
496 {
497 type = ReadID();
498 if (type == NID::kEnd)
499 break;
500 if (type == NID::kCRC)
501 {
502 ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs);
503 continue;
504 }
505 SkeepData();
506 }
507 if (packCRCsDefined.IsEmpty())
508 {
509 BoolVector_Fill_False(packCRCsDefined, numPackStreams);
510 packCRCs.Reserve(numPackStreams);
511 packCRCs.Clear();
512 for (CNum i = 0; i < numPackStreams; i++)
513 packCRCs.Add(0);
514 }
515 }
517 void CInArchive::ReadUnpackInfo(
518 const CObjectVector<CByteBuffer> *dataVector,
519 CObjectVector<CFolder> &folders)
520 {
521 WaitAttribute(NID::kFolder);
522 CNum numFolders = ReadNum();
524 {
525 CStreamSwitch streamSwitch;
526 streamSwitch.Set(this, dataVector);
527 folders.Clear();
528 folders.Reserve(numFolders);
529 for (CNum i = 0; i < numFolders; i++)
530 {
531 folders.Add(CFolder());
532 GetNextFolderItem(folders.Back());
533 }
534 }
536 WaitAttribute(NID::kCodersUnpackSize);
538 CNum i;
539 for (i = 0; i < numFolders; i++)
540 {
541 CFolder &folder = folders[i];
542 CNum numOutStreams = folder.GetNumOutStreams();
543 folder.UnpackSizes.Reserve(numOutStreams);
544 for (CNum j = 0; j < numOutStreams; j++)
545 folder.UnpackSizes.Add(ReadNumber());
546 }
548 for (;;)
549 {
550 UInt64 type = ReadID();
551 if (type == NID::kEnd)
552 return;
553 if (type == NID::kCRC)
554 {
555 CBoolVector crcsDefined;
556 CRecordVector<UInt32> crcs;
557 ReadHashDigests(numFolders, crcsDefined, crcs);
558 for (i = 0; i < numFolders; i++)
559 {
560 CFolder &folder = folders[i];
561 folder.UnpackCRCDefined = crcsDefined[i];
562 folder.UnpackCRC = crcs[i];
563 }
564 continue;
565 }
566 SkeepData();
567 }
568 }
570 void CInArchive::ReadSubStreamsInfo(
571 const CObjectVector<CFolder> &folders,
572 CRecordVector<CNum> &numUnpackStreamsInFolders,
573 CRecordVector<UInt64> &unpackSizes,
574 CBoolVector &digestsDefined,
575 CRecordVector<UInt32> &digests)
576 {
577 numUnpackStreamsInFolders.Clear();
578 numUnpackStreamsInFolders.Reserve(folders.Size());
579 UInt64 type;
580 for (;;)
581 {
582 type = ReadID();
583 if (type == NID::kNumUnpackStream)
584 {
585 for (int i = 0; i < folders.Size(); i++)
586 numUnpackStreamsInFolders.Add(ReadNum());
587 continue;
588 }
589 if (type == NID::kCRC || type == NID::kSize)
590 break;
591 if (type == NID::kEnd)
592 break;
593 SkeepData();
594 }
596 if (numUnpackStreamsInFolders.IsEmpty())
597 for (int i = 0; i < folders.Size(); i++)
598 numUnpackStreamsInFolders.Add(1);
600 int i;
601 for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
602 {
603 // v3.13 incorrectly worked with empty folders
604 // v4.07: we check that folder is empty
605 CNum numSubstreams = numUnpackStreamsInFolders[i];
606 if (numSubstreams == 0)
607 continue;
608 UInt64 sum = 0;
609 for (CNum j = 1; j < numSubstreams; j++)
610 if (type == NID::kSize)
611 {
612 UInt64 size = ReadNumber();
613 unpackSizes.Add(size);
614 sum += size;
615 }
616 unpackSizes.Add(folders[i].GetUnpackSize() - sum);
617 }
618 if (type == NID::kSize)
619 type = ReadID();
621 int numDigests = 0;
622 int numDigestsTotal = 0;
623 for (i = 0; i < folders.Size(); i++)
624 {
625 CNum numSubstreams = numUnpackStreamsInFolders[i];
626 if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
627 numDigests += numSubstreams;
628 numDigestsTotal += numSubstreams;
629 }
631 for (;;)
632 {
633 if (type == NID::kCRC)
634 {
635 CBoolVector digestsDefined2;
636 CRecordVector<UInt32> digests2;
637 ReadHashDigests(numDigests, digestsDefined2, digests2);
638 int digestIndex = 0;
639 for (i = 0; i < folders.Size(); i++)
640 {
641 CNum numSubstreams = numUnpackStreamsInFolders[i];
642 const CFolder &folder = folders[i];
643 if (numSubstreams == 1 && folder.UnpackCRCDefined)
644 {
645 digestsDefined.Add(true);
646 digests.Add(folder.UnpackCRC);
647 }
648 else
649 for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
650 {
651 digestsDefined.Add(digestsDefined2[digestIndex]);
652 digests.Add(digests2[digestIndex]);
653 }
654 }
655 }
656 else if (type == NID::kEnd)
657 {
658 if (digestsDefined.IsEmpty())
659 {
660 BoolVector_Fill_False(digestsDefined, numDigestsTotal);
661 digests.Clear();
662 for (int i = 0; i < numDigestsTotal; i++)
663 digests.Add(0);
664 }
665 return;
666 }
667 else
668 SkeepData();
669 type = ReadID();
670 }
671 }
673 void CInArchive::ReadStreamsInfo(
674 const CObjectVector<CByteBuffer> *dataVector,
675 UInt64 &dataOffset,
676 CRecordVector<UInt64> &packSizes,
677 CBoolVector &packCRCsDefined,
678 CRecordVector<UInt32> &packCRCs,
679 CObjectVector<CFolder> &folders,
680 CRecordVector<CNum> &numUnpackStreamsInFolders,
681 CRecordVector<UInt64> &unpackSizes,
682 CBoolVector &digestsDefined,
683 CRecordVector<UInt32> &digests)
684 {
685 for (;;)
686 {
687 UInt64 type = ReadID();
688 if (type > ((UInt32)1 << 30))
689 ThrowIncorrect();
690 switch((UInt32)type)
691 {
692 case NID::kEnd:
693 return;
694 case NID::kPackInfo:
695 {
696 ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
697 break;
698 }
699 case NID::kUnpackInfo:
700 {
701 ReadUnpackInfo(dataVector, folders);
702 break;
703 }
704 case NID::kSubStreamsInfo:
705 {
706 ReadSubStreamsInfo(folders, numUnpackStreamsInFolders,
707 unpackSizes, digestsDefined, digests);
708 break;
709 }
710 default:
711 ThrowIncorrect();
712 }
713 }
714 }
716 void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
717 {
718 v.Clear();
719 v.Reserve(numItems);
720 Byte b = 0;
721 Byte mask = 0;
722 for (int i = 0; i < numItems; i++)
723 {
724 if (mask == 0)
725 {
726 b = ReadByte();
727 mask = 0x80;
728 }
729 v.Add((b & mask) != 0);
730 mask >>= 1;
731 }
732 }
734 void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
735 {
736 Byte allAreDefined = ReadByte();
737 if (allAreDefined == 0)
738 {
739 ReadBoolVector(numItems, v);
740 return;
741 }
742 v.Clear();
743 v.Reserve(numItems);
744 for (int i = 0; i < numItems; i++)
745 v.Add(true);
746 }
748 void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
749 CUInt64DefVector &v, int numFiles)
750 {
751 ReadBoolVector2(numFiles, v.Defined);
753 CStreamSwitch streamSwitch;
754 streamSwitch.Set(this, &dataVector);
755 v.Values.Reserve(numFiles);
757 for (int i = 0; i < numFiles; i++)
758 {
759 UInt64 t = 0;
760 if (v.Defined[i])
761 t = ReadUInt64();
762 v.Values.Add(t);
763 }
764 }
766 HRESULT CInArchive::ReadAndDecodePackedStreams(
767 DECL_EXTERNAL_CODECS_LOC_VARS
768 UInt64 baseOffset,
769 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
770 #ifndef _NO_CRYPTO
771 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
772 #endif
773 )
774 {
775 CRecordVector<UInt64> packSizes;
776 CBoolVector packCRCsDefined;
777 CRecordVector<UInt32> packCRCs;
778 CObjectVector<CFolder> folders;
780 CRecordVector<CNum> numUnpackStreamsInFolders;
781 CRecordVector<UInt64> unpackSizes;
782 CBoolVector digestsDefined;
783 CRecordVector<UInt32> digests;
785 ReadStreamsInfo(NULL,
786 dataOffset,
787 packSizes,
788 packCRCsDefined,
789 packCRCs,
790 folders,
791 numUnpackStreamsInFolders,
792 unpackSizes,
793 digestsDefined,
794 digests);
796 // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
798 CNum packIndex = 0;
799 CDecoder decoder(
800 #ifdef _ST_MODE
801 false
802 #else
803 true
804 #endif
805 );
806 UInt64 dataStartPos = baseOffset + dataOffset;
807 for (int i = 0; i < folders.Size(); i++)
808 {
809 const CFolder &folder = folders[i];
810 dataVector.Add(CByteBuffer());
811 CByteBuffer &data = dataVector.Back();
812 UInt64 unpackSize64 = folder.GetUnpackSize();
813 size_t unpackSize = (size_t)unpackSize64;
814 if (unpackSize != unpackSize64)
815 ThrowUnsupported();
816 data.SetCapacity(unpackSize);
818 CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
819 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
820 outStreamSpec->Init(data, unpackSize);
822 HRESULT result = decoder.Decode(
823 EXTERNAL_CODECS_LOC_VARS
824 _stream, dataStartPos,
825 &packSizes[packIndex], folder, outStream, NULL
826 #ifndef _NO_CRYPTO
827 , getTextPassword, passwordIsDefined
828 #endif
829 #ifdef COMPRESS_MT
830 , false, 1
831 #endif
832 );
833 RINOK(result);
835 if (folder.UnpackCRCDefined)
836 if (CrcCalc(data, unpackSize) != folder.UnpackCRC)
837 ThrowIncorrect();
838 for (int j = 0; j < folder.PackStreams.Size(); j++)
839 {
840 UInt64 packSize = packSizes[packIndex++];
841 dataStartPos += packSize;
842 HeadersSize += packSize;
843 }
844 }
845 return S_OK;
846 }
848 HRESULT CInArchive::ReadHeader(
849 DECL_EXTERNAL_CODECS_LOC_VARS
850 CArchiveDatabaseEx &db
851 #ifndef _NO_CRYPTO
852 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
853 #endif
854 )
855 {
856 UInt64 type = ReadID();
858 if (type == NID::kArchiveProperties)
859 {
860 ReadArchiveProperties(db.ArchiveInfo);
861 type = ReadID();
862 }
864 CObjectVector<CByteBuffer> dataVector;
866 if (type == NID::kAdditionalStreamsInfo)
867 {
868 HRESULT result = ReadAndDecodePackedStreams(
869 EXTERNAL_CODECS_LOC_VARS
870 db.ArchiveInfo.StartPositionAfterHeader,
871 db.ArchiveInfo.DataStartPosition2,
872 dataVector
873 #ifndef _NO_CRYPTO
874 , getTextPassword, passwordIsDefined
875 #endif
876 );
877 RINOK(result);
878 db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
879 type = ReadID();
880 }
882 CRecordVector<UInt64> unpackSizes;
883 CBoolVector digestsDefined;
884 CRecordVector<UInt32> digests;
886 if (type == NID::kMainStreamsInfo)
887 {
888 ReadStreamsInfo(&dataVector,
889 db.ArchiveInfo.DataStartPosition,
890 db.PackSizes,
891 db.PackCRCsDefined,
892 db.PackCRCs,
893 db.Folders,
894 db.NumUnpackStreamsVector,
895 unpackSizes,
896 digestsDefined,
897 digests);
898 db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader;
899 type = ReadID();
900 }
901 else
902 {
903 for (int i = 0; i < db.Folders.Size(); i++)
904 {
905 db.NumUnpackStreamsVector.Add(1);
906 CFolder &folder = db.Folders[i];
907 unpackSizes.Add(folder.GetUnpackSize());
908 digestsDefined.Add(folder.UnpackCRCDefined);
909 digests.Add(folder.UnpackCRC);
910 }
911 }
913 db.Files.Clear();
915 if (type == NID::kEnd)
916 return S_OK;
917 if (type != NID::kFilesInfo)
918 ThrowIncorrect();
920 CNum numFiles = ReadNum();
921 db.Files.Reserve(numFiles);
922 CNum i;
923 for (i = 0; i < numFiles; i++)
924 db.Files.Add(CFileItem());
926 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
927 if (!db.PackSizes.IsEmpty())
928 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
929 if (numFiles > 0 && !digests.IsEmpty())
930 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
932 CBoolVector emptyStreamVector;
933 BoolVector_Fill_False(emptyStreamVector, (int)numFiles);
934 CBoolVector emptyFileVector;
935 CBoolVector antiFileVector;
936 CNum numEmptyStreams = 0;
938 for (;;)
939 {
940 UInt64 type = ReadID();
941 if (type == NID::kEnd)
942 break;
943 UInt64 size = ReadNumber();
944 size_t ppp = _inByteBack->_pos;
945 bool addPropIdToList = true;
946 bool isKnownType = true;
947 if (type > ((UInt32)1 << 30))
948 isKnownType = false;
949 else switch((UInt32)type)
950 {
951 case NID::kName:
952 {
953 CStreamSwitch streamSwitch;
954 streamSwitch.Set(this, &dataVector);
955 for (int i = 0; i < db.Files.Size(); i++)
956 _inByteBack->ReadString(db.Files[i].Name);
957 break;
958 }
959 case NID::kWinAttributes:
960 {
961 CBoolVector boolVector;
962 ReadBoolVector2(db.Files.Size(), boolVector);
963 CStreamSwitch streamSwitch;
964 streamSwitch.Set(this, &dataVector);
965 for (i = 0; i < numFiles; i++)
966 {
967 CFileItem &file = db.Files[i];
968 file.AttribDefined = boolVector[i];
969 if (file.AttribDefined)
970 file.Attrib = ReadUInt32();
971 }
972 break;
973 }
974 case NID::kEmptyStream:
975 {
976 ReadBoolVector(numFiles, emptyStreamVector);
977 for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
978 if (emptyStreamVector[i])
979 numEmptyStreams++;
981 BoolVector_Fill_False(emptyFileVector, numEmptyStreams);
982 BoolVector_Fill_False(antiFileVector, numEmptyStreams);
984 break;
985 }
986 case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break;
987 case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break;
988 case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break;
989 case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break;
990 case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break;
991 case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break;
992 case NID::kDummy:
993 {
994 for (UInt64 j = 0; j < size; j++)
995 if (ReadByte() != 0)
996 ThrowIncorrect();
997 addPropIdToList = false;
998 break;
999 }
1000 default:
1001 addPropIdToList = isKnownType = false;
1003 if (isKnownType)
1005 if(addPropIdToList)
1006 db.ArchiveInfo.FileInfoPopIDs.Add(type);
1008 else
1009 SkeepData(size);
1010 bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 ||
1011 db.ArchiveInfo.Version.Minor > 2);
1012 if (checkRecordsSize && _inByteBack->_pos - ppp != size)
1013 ThrowIncorrect();
1016 CNum emptyFileIndex = 0;
1017 CNum sizeIndex = 0;
1019 CNum numAntiItems = 0;
1020 for (i = 0; i < numEmptyStreams; i++)
1021 if (antiFileVector[i])
1022 numAntiItems++;
1024 for (i = 0; i < numFiles; i++)
1026 CFileItem &file = db.Files[i];
1027 bool isAnti;
1028 file.HasStream = !emptyStreamVector[i];
1029 if (file.HasStream)
1031 file.IsDir = false;
1032 isAnti = false;
1033 file.Size = unpackSizes[sizeIndex];
1034 file.Crc = digests[sizeIndex];
1035 file.CrcDefined = digestsDefined[sizeIndex];
1036 sizeIndex++;
1038 else
1040 file.IsDir = !emptyFileVector[emptyFileIndex];
1041 isAnti = antiFileVector[emptyFileIndex];
1042 emptyFileIndex++;
1043 file.Size = 0;
1044 file.CrcDefined = false;
1046 if (numAntiItems != 0)
1047 db.IsAnti.Add(isAnti);
1049 return S_OK;
1053 void CArchiveDatabaseEx::FillFolderStartPackStream()
1055 FolderStartPackStreamIndex.Clear();
1056 FolderStartPackStreamIndex.Reserve(Folders.Size());
1057 CNum startPos = 0;
1058 for (int i = 0; i < Folders.Size(); i++)
1060 FolderStartPackStreamIndex.Add(startPos);
1061 startPos += (CNum)Folders[i].PackStreams.Size();
1065 void CArchiveDatabaseEx::FillStartPos()
1067 PackStreamStartPositions.Clear();
1068 PackStreamStartPositions.Reserve(PackSizes.Size());
1069 UInt64 startPos = 0;
1070 for (int i = 0; i < PackSizes.Size(); i++)
1072 PackStreamStartPositions.Add(startPos);
1073 startPos += PackSizes[i];
1077 void CArchiveDatabaseEx::FillFolderStartFileIndex()
1079 FolderStartFileIndex.Clear();
1080 FolderStartFileIndex.Reserve(Folders.Size());
1081 FileIndexToFolderIndexMap.Clear();
1082 FileIndexToFolderIndexMap.Reserve(Files.Size());
1084 int folderIndex = 0;
1085 CNum indexInFolder = 0;
1086 for (int i = 0; i < Files.Size(); i++)
1088 const CFileItem &file = Files[i];
1089 bool emptyStream = !file.HasStream;
1090 if (emptyStream && indexInFolder == 0)
1092 FileIndexToFolderIndexMap.Add(kNumNoIndex);
1093 continue;
1095 if (indexInFolder == 0)
1097 // v3.13 incorrectly worked with empty folders
1098 // v4.07: Loop for skipping empty folders
1099 for (;;)
1101 if (folderIndex >= Folders.Size())
1102 ThrowIncorrect();
1103 FolderStartFileIndex.Add(i); // check it
1104 if (NumUnpackStreamsVector[folderIndex] != 0)
1105 break;
1106 folderIndex++;
1109 FileIndexToFolderIndexMap.Add(folderIndex);
1110 if (emptyStream)
1111 continue;
1112 indexInFolder++;
1113 if (indexInFolder >= NumUnpackStreamsVector[folderIndex])
1115 folderIndex++;
1116 indexInFolder = 0;
1121 HRESULT CInArchive::ReadDatabase2(
1122 DECL_EXTERNAL_CODECS_LOC_VARS
1123 CArchiveDatabaseEx &db
1124 #ifndef _NO_CRYPTO
1125 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
1126 #endif
1129 db.Clear();
1130 db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
1132 db.ArchiveInfo.Version.Major = _header[6];
1133 db.ArchiveInfo.Version.Minor = _header[7];
1135 if (db.ArchiveInfo.Version.Major != kMajorVersion)
1136 ThrowUnsupportedVersion();
1138 UInt32 crcFromArchive = Get32(_header + 8);
1139 UInt64 nextHeaderOffset = Get64(_header + 0xC);
1140 UInt64 nextHeaderSize = Get64(_header + 0x14);
1141 UInt32 nextHeaderCRC = Get32(_header + 0x1C);
1142 UInt32 crc = CrcCalc(_header + 0xC, 20);
1144 #ifdef FORMAT_7Z_RECOVERY
1145 if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
1147 UInt64 cur, cur2;
1148 RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
1149 const int kCheckSize = 500;
1150 Byte buf[kCheckSize];
1151 RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
1152 int checkSize = kCheckSize;
1153 if (cur2 - cur < kCheckSize)
1154 checkSize = (int)(cur2 - cur);
1155 RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
1157 RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));
1159 int i;
1160 for (i = (int)checkSize - 2; i >= 0; i--)
1161 if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
1162 break;
1163 if (i < 0)
1164 return S_FALSE;
1165 nextHeaderSize = checkSize - i;
1166 nextHeaderOffset = cur2 - cur + i;
1167 nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
1168 RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
1170 #endif
1172 #ifdef FORMAT_7Z_RECOVERY
1173 crcFromArchive = crc;
1174 #endif
1176 db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
1178 if (crc != crcFromArchive)
1179 ThrowIncorrect();
1181 if (nextHeaderSize == 0)
1182 return S_OK;
1184 if (nextHeaderSize > (UInt64)0xFFFFFFFF)
1185 return S_FALSE;
1187 RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
1189 CByteBuffer buffer2;
1190 buffer2.SetCapacity((size_t)nextHeaderSize);
1192 RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize));
1193 HeadersSize += kHeaderSize + nextHeaderSize;
1194 db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
1196 if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
1197 ThrowIncorrect();
1199 CStreamSwitch streamSwitch;
1200 streamSwitch.Set(this, buffer2);
1202 CObjectVector<CByteBuffer> dataVector;
1204 UInt64 type = ReadID();
1205 if (type != NID::kHeader)
1207 if (type != NID::kEncodedHeader)
1208 ThrowIncorrect();
1209 HRESULT result = ReadAndDecodePackedStreams(
1210 EXTERNAL_CODECS_LOC_VARS
1211 db.ArchiveInfo.StartPositionAfterHeader,
1212 db.ArchiveInfo.DataStartPosition2,
1213 dataVector
1214 #ifndef _NO_CRYPTO
1215 , getTextPassword, passwordIsDefined
1216 #endif
1217 );
1218 RINOK(result);
1219 if (dataVector.Size() == 0)
1220 return S_OK;
1221 if (dataVector.Size() > 1)
1222 ThrowIncorrect();
1223 streamSwitch.Remove();
1224 streamSwitch.Set(this, dataVector.Front());
1225 if (ReadID() != NID::kHeader)
1226 ThrowIncorrect();
1229 db.HeadersSize = HeadersSize;
1231 return ReadHeader(
1232 EXTERNAL_CODECS_LOC_VARS
1233 db
1234 #ifndef _NO_CRYPTO
1235 , getTextPassword, passwordIsDefined
1236 #endif
1237 );
1240 HRESULT CInArchive::ReadDatabase(
1241 DECL_EXTERNAL_CODECS_LOC_VARS
1242 CArchiveDatabaseEx &db
1243 #ifndef _NO_CRYPTO
1244 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
1245 #endif
1248 try
1250 return ReadDatabase2(
1251 EXTERNAL_CODECS_LOC_VARS db
1252 #ifndef _NO_CRYPTO
1253 , getTextPassword, passwordIsDefined
1254 #endif
1255 );
1257 catch(CInArchiveException &) { return S_FALSE; }
1260 }}