Mercurial > vba-linux
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.cpp3 #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 StartHeader22 #ifndef _SFX23 #define FORMAT_7Z_RECOVERY24 #endif26 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() const47 {48 const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it49 const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax50 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 CInArchiveException119 {120 public:121 enum CCauseType122 {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 CStreamSwitch139 {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 do314 {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 archive345 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 else402 {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 else446 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 folders604 // v4.07: we check that folder is empty605 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 else649 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 else668 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_VARS768 UInt64 baseOffset,769 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector770 #ifndef _NO_CRYPTO771 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined772 #endif773 )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_MODE801 false802 #else803 true804 #endif805 );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_VARS824 _stream, dataStartPos,825 &packSizes[packIndex], folder, outStream, NULL826 #ifndef _NO_CRYPTO827 , getTextPassword, passwordIsDefined828 #endif829 #ifdef COMPRESS_MT830 , false, 1831 #endif832 );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_VARS850 CArchiveDatabaseEx &db851 #ifndef _NO_CRYPTO852 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined853 #endif854 )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_VARS870 db.ArchiveInfo.StartPositionAfterHeader,871 db.ArchiveInfo.DataStartPosition2,872 dataVector873 #ifndef _NO_CRYPTO874 , getTextPassword, passwordIsDefined875 #endif876 );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 else902 {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;1002 }1003 if (isKnownType)1004 {1005 if(addPropIdToList)1006 db.ArchiveInfo.FileInfoPopIDs.Add(type);1007 }1008 else1009 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();1014 }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++)1025 {1026 CFileItem &file = db.Files[i];1027 bool isAnti;1028 file.HasStream = !emptyStreamVector[i];1029 if (file.HasStream)1030 {1031 file.IsDir = false;1032 isAnti = false;1033 file.Size = unpackSizes[sizeIndex];1034 file.Crc = digests[sizeIndex];1035 file.CrcDefined = digestsDefined[sizeIndex];1036 sizeIndex++;1037 }1038 else1039 {1040 file.IsDir = !emptyFileVector[emptyFileIndex];1041 isAnti = antiFileVector[emptyFileIndex];1042 emptyFileIndex++;1043 file.Size = 0;1044 file.CrcDefined = false;1045 }1046 if (numAntiItems != 0)1047 db.IsAnti.Add(isAnti);1048 }1049 return S_OK;1050 }1053 void CArchiveDatabaseEx::FillFolderStartPackStream()1054 {1055 FolderStartPackStreamIndex.Clear();1056 FolderStartPackStreamIndex.Reserve(Folders.Size());1057 CNum startPos = 0;1058 for (int i = 0; i < Folders.Size(); i++)1059 {1060 FolderStartPackStreamIndex.Add(startPos);1061 startPos += (CNum)Folders[i].PackStreams.Size();1062 }1063 }1065 void CArchiveDatabaseEx::FillStartPos()1066 {1067 PackStreamStartPositions.Clear();1068 PackStreamStartPositions.Reserve(PackSizes.Size());1069 UInt64 startPos = 0;1070 for (int i = 0; i < PackSizes.Size(); i++)1071 {1072 PackStreamStartPositions.Add(startPos);1073 startPos += PackSizes[i];1074 }1075 }1077 void CArchiveDatabaseEx::FillFolderStartFileIndex()1078 {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++)1087 {1088 const CFileItem &file = Files[i];1089 bool emptyStream = !file.HasStream;1090 if (emptyStream && indexInFolder == 0)1091 {1092 FileIndexToFolderIndexMap.Add(kNumNoIndex);1093 continue;1094 }1095 if (indexInFolder == 0)1096 {1097 // v3.13 incorrectly worked with empty folders1098 // v4.07: Loop for skipping empty folders1099 for (;;)1100 {1101 if (folderIndex >= Folders.Size())1102 ThrowIncorrect();1103 FolderStartFileIndex.Add(i); // check it1104 if (NumUnpackStreamsVector[folderIndex] != 0)1105 break;1106 folderIndex++;1107 }1108 }1109 FileIndexToFolderIndexMap.Add(folderIndex);1110 if (emptyStream)1111 continue;1112 indexInFolder++;1113 if (indexInFolder >= NumUnpackStreamsVector[folderIndex])1114 {1115 folderIndex++;1116 indexInFolder = 0;1117 }1118 }1119 }1121 HRESULT CInArchive::ReadDatabase2(1122 DECL_EXTERNAL_CODECS_LOC_VARS1123 CArchiveDatabaseEx &db1124 #ifndef _NO_CRYPTO1125 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined1126 #endif1127 )1128 {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_RECOVERY1145 if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)1146 {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));1169 }1170 #endif1172 #ifdef FORMAT_7Z_RECOVERY1173 crcFromArchive = crc;1174 #endif1176 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)1206 {1207 if (type != NID::kEncodedHeader)1208 ThrowIncorrect();1209 HRESULT result = ReadAndDecodePackedStreams(1210 EXTERNAL_CODECS_LOC_VARS1211 db.ArchiveInfo.StartPositionAfterHeader,1212 db.ArchiveInfo.DataStartPosition2,1213 dataVector1214 #ifndef _NO_CRYPTO1215 , getTextPassword, passwordIsDefined1216 #endif1217 );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();1227 }1229 db.HeadersSize = HeadersSize;1231 return ReadHeader(1232 EXTERNAL_CODECS_LOC_VARS1233 db1234 #ifndef _NO_CRYPTO1235 , getTextPassword, passwordIsDefined1236 #endif1237 );1238 }1240 HRESULT CInArchive::ReadDatabase(1241 DECL_EXTERNAL_CODECS_LOC_VARS1242 CArchiveDatabaseEx &db1243 #ifndef _NO_CRYPTO1244 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined1245 #endif1246 )1247 {1248 try1249 {1250 return ReadDatabase2(1251 EXTERNAL_CODECS_LOC_VARS db1252 #ifndef _NO_CRYPTO1253 , getTextPassword, passwordIsDefined1254 #endif1255 );1256 }1257 catch(CInArchiveException &) { return S_FALSE; }1258 }1260 }}