7zin.cpp
来自「由7-zip提供的压缩、解压缩程序」· C++ 代码 · 共 1,295 行 · 第 1/3 页
CPP
1,295 行
dataVector.Add(CByteBuffer()); CByteBuffer &data = dataVector.Back(); UInt64 unPackSize = folder.GetUnPackSize(); if (unPackSize > kNumMax) return E_FAIL; if (unPackSize > 0xFFFFFFFF) return E_FAIL; data.SetCapacity((size_t)unPackSize); CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2; CMyComPtr<ISequentialOutStream> outStream = outStreamSpec; outStreamSpec->Init(data, (size_t)unPackSize); HRESULT result = decoder.Decode(_stream, dataStartPos, &packSizes[packIndex], folder, outStream, NULL #ifndef _NO_CRYPTO , getTextPassword #endif #ifdef COMPRESS_MT , false, 1 #endif ); RINOK(result); if (folder.UnPackCRCDefined) if (!CCRC::VerifyDigest(folder.UnPackCRC, data, (UInt32)unPackSize)) throw CInArchiveException(CInArchiveException::kIncorrectHeader); for (int j = 0; j < folder.PackStreams.Size(); j++) dataStartPos += packSizes[packIndex++]; } return S_OK;}HRESULT CInArchive::ReadHeader(CArchiveDatabaseEx &database #ifndef _NO_CRYPTO , ICryptoGetTextPassword *getTextPassword #endif ){ UInt64 type; RINOK(ReadID(type)); if (type == NID::kArchiveProperties) { RINOK(ReadArchiveProperties(database.ArchiveInfo)); RINOK(ReadID(type)); } CObjectVector<CByteBuffer> dataVector; if (type == NID::kAdditionalStreamsInfo) { HRESULT result = ReadAndDecodePackedStreams( database.ArchiveInfo.StartPositionAfterHeader, database.ArchiveInfo.DataStartPosition2, dataVector #ifndef _NO_CRYPTO , getTextPassword #endif ); RINOK(result); database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader; RINOK(ReadID(type)); } CRecordVector<UInt64> unPackSizes; CRecordVector<bool> digestsDefined; CRecordVector<UInt32> digests; if (type == NID::kMainStreamsInfo) { RINOK(ReadStreamsInfo(&dataVector, database.ArchiveInfo.DataStartPosition, database.PackSizes, database.PackCRCsDefined, database.PackCRCs, database.Folders, database.NumUnPackStreamsVector, unPackSizes, digestsDefined, digests)); database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader; RINOK(ReadID(type)); } else { for(int i = 0; i < database.Folders.Size(); i++) { database.NumUnPackStreamsVector.Add(1); CFolder &folder = database.Folders[i]; unPackSizes.Add(folder.GetUnPackSize()); digestsDefined.Add(folder.UnPackCRCDefined); digests.Add(folder.UnPackCRC); } } database.Files.Clear(); if (type == NID::kEnd) return S_OK; if (type != NID::kFilesInfo) throw CInArchiveException(CInArchiveException::kIncorrectHeader); CNum numFiles; RINOK(ReadNum(numFiles)); database.Files.Reserve(numFiles); CNum i; for(i = 0; i < numFiles; i++) database.Files.Add(CFileItem()); database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize); if (!database.PackSizes.IsEmpty()) database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo); if (numFiles > 0 && !digests.IsEmpty()) database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC); CBoolVector emptyStreamVector; emptyStreamVector.Reserve((int)numFiles); for(i = 0; i < numFiles; i++) emptyStreamVector.Add(false); CBoolVector emptyFileVector; CBoolVector antiFileVector; CNum numEmptyStreams = 0; // int sizePrev = -1; // int posPrev = 0; while(true) { /* if (sizePrev >= 0) if (sizePrev != _inByteBack->GetProcessedSize() - posPrev) throw 2; */ UInt64 type; RINOK(ReadID(type)); if (type == NID::kEnd) break; UInt64 size; RINOK(ReadNumber(size)); // sizePrev = size; // posPrev = _inByteBack->GetProcessedSize(); database.ArchiveInfo.FileInfoPopIDs.Add(type); switch(type) { case NID::kName: { CStreamSwitch streamSwitch; RINOK(streamSwitch.Set(this, &dataVector)); RINOK(ReadFileNames(database.Files)) break; } case NID::kWinAttributes: { CBoolVector boolVector; RINOK(ReadBoolVector2(database.Files.Size(), boolVector)) CStreamSwitch streamSwitch; RINOK(streamSwitch.Set(this, &dataVector)); for(i = 0; i < numFiles; i++) { CFileItem &file = database.Files[i]; if (file.AreAttributesDefined = boolVector[i]) { RINOK(ReadUInt32(file.Attributes)); } } break; } case NID::kStartPos: { CBoolVector boolVector; RINOK(ReadBoolVector2(database.Files.Size(), boolVector)) CStreamSwitch streamSwitch; RINOK(streamSwitch.Set(this, &dataVector)); for(i = 0; i < numFiles; i++) { CFileItem &file = database.Files[i]; if (file.IsStartPosDefined = boolVector[i]) { RINOK(ReadUInt64(file.StartPos)); } } break; } case NID::kEmptyStream: { RINOK(ReadBoolVector(numFiles, emptyStreamVector)) for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) if (emptyStreamVector[i]) numEmptyStreams++; emptyFileVector.Reserve(numEmptyStreams); antiFileVector.Reserve(numEmptyStreams); for (i = 0; i < numEmptyStreams; i++) { emptyFileVector.Add(false); antiFileVector.Add(false); } break; } case NID::kEmptyFile: { RINOK(ReadBoolVector(numEmptyStreams, emptyFileVector)) break; } case NID::kAnti: { RINOK(ReadBoolVector(numEmptyStreams, antiFileVector)) break; } case NID::kCreationTime: case NID::kLastWriteTime: case NID::kLastAccessTime: { RINOK(ReadTime(dataVector, database.Files, type)) break; } default: { database.ArchiveInfo.FileInfoPopIDs.DeleteBack(); RINOK(SkeepData(size)); } } } CNum emptyFileIndex = 0; CNum sizeIndex = 0; for(i = 0; i < numFiles; i++) { CFileItem &file = database.Files[i]; file.HasStream = !emptyStreamVector[i]; if(file.HasStream) { file.IsDirectory = false; file.IsAnti = false; file.UnPackSize = unPackSizes[sizeIndex]; file.FileCRC = digests[sizeIndex]; file.IsFileCRCDefined = digestsDefined[sizeIndex]; sizeIndex++; } else { file.IsDirectory = !emptyFileVector[emptyFileIndex]; file.IsAnti = antiFileVector[emptyFileIndex]; emptyFileIndex++; file.UnPackSize = 0; file.IsFileCRCDefined = false; } } return S_OK;}void CArchiveDatabaseEx::FillFolderStartPackStream(){ FolderStartPackStreamIndex.Clear(); FolderStartPackStreamIndex.Reserve(Folders.Size()); CNum startPos = 0; for(int i = 0; i < Folders.Size(); i++) { FolderStartPackStreamIndex.Add(startPos); startPos += (CNum)Folders[i].PackStreams.Size(); }}void CArchiveDatabaseEx::FillStartPos(){ PackStreamStartPositions.Clear(); PackStreamStartPositions.Reserve(PackSizes.Size()); UInt64 startPos = 0; for(int i = 0; i < PackSizes.Size(); i++) { PackStreamStartPositions.Add(startPos); startPos += PackSizes[i]; }}void CArchiveDatabaseEx::FillFolderStartFileIndex(){ FolderStartFileIndex.Clear(); FolderStartFileIndex.Reserve(Folders.Size()); FileIndexToFolderIndexMap.Clear(); FileIndexToFolderIndexMap.Reserve(Files.Size()); int folderIndex = 0; CNum indexInFolder = 0; for (int i = 0; i < Files.Size(); i++) { const CFileItem &file = Files[i]; bool emptyStream = !file.HasStream; if (emptyStream && indexInFolder == 0) { FileIndexToFolderIndexMap.Add(kNumNoIndex); continue; } if (indexInFolder == 0) { // v3.13 incorrectly worked with empty folders // v4.07: Loop for skipping empty folders while(true) { if (folderIndex >= Folders.Size()) throw CInArchiveException(CInArchiveException::kIncorrectHeader); FolderStartFileIndex.Add(i); // check it if (NumUnPackStreamsVector[folderIndex] != 0) break; folderIndex++; } } FileIndexToFolderIndexMap.Add(folderIndex); if (emptyStream) continue; indexInFolder++; if (indexInFolder >= NumUnPackStreamsVector[folderIndex]) { folderIndex++; indexInFolder = 0; } }}HRESULT CInArchive::ReadDatabase(CArchiveDatabaseEx &database #ifndef _NO_CRYPTO , ICryptoGetTextPassword *getTextPassword #endif ){ database.Clear(); database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition; RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Major, 1)); RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Minor, 1)); if (database.ArchiveInfo.Version.Major != kMajorVersion) throw CInArchiveException(CInArchiveException::kUnsupportedVersion); #ifdef _7Z_VOL if (_finishSignature) { RINOK(_stream->Seek(_position - (4 + kFinishHeaderSize) - (kSignatureSize + 2), STREAM_SEEK_SET, &_position)); } #endif UInt32 crcFromArchive; RINOK(SafeReadDirectUInt32(crcFromArchive)); UInt64 nextHeaderOffset; UInt64 nextHeaderSize; UInt32 nextHeaderCRC; CCRC crc; RINOK(SafeReadDirectUInt64(nextHeaderOffset)); crc.UpdateUInt64(nextHeaderOffset); RINOK(SafeReadDirectUInt64(nextHeaderSize)); crc.UpdateUInt64(nextHeaderSize); RINOK(SafeReadDirectUInt32(nextHeaderCRC)); crc.UpdateUInt32(nextHeaderCRC); #ifdef _7Z_VOL UInt64 archiveStartOffset; // data offset from end if that struct UInt64 additionalStartBlockSize; // start signature & start header size if (_finishSignature) { RINOK(SafeReadDirectUInt64(archiveStartOffset)); crc.UpdateUInt64(archiveStartOffset); RINOK(SafeReadDirectUInt64(additionalStartBlockSize)); crc.UpdateUInt64(additionalStartBlockSize); database.ArchiveInfo.StartPositionAfterHeader = _position + archiveStartOffset; } else #endif { database.ArchiveInfo.StartPositionAfterHeader = _position; } if (crc.GetDigest() != crcFromArchive) throw CInArchiveException(CInArchiveException::kIncorrectHeader); if (nextHeaderSize == 0) return S_OK; if (nextHeaderSize >= 0xFFFFFFFF) return E_FAIL; RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, &_position)); CByteBuffer buffer2; buffer2.SetCapacity((size_t)nextHeaderSize); RINOK(SafeReadDirect(buffer2, (UInt32)nextHeaderSize)); if (!CCRC::VerifyDigest(nextHeaderCRC, buffer2, (UInt32)nextHeaderSize)) throw CInArchiveException(CInArchiveException::kIncorrectHeader); CStreamSwitch streamSwitch; streamSwitch.Set(this, buffer2); CObjectVector<CByteBuffer> dataVector; while (true) { UInt64 type; RINOK(ReadID(type)); if (type == NID::kHeader) break; if (type != NID::kEncodedHeader) throw CInArchiveException(CInArchiveException::kIncorrectHeader); HRESULT result = ReadAndDecodePackedStreams( database.ArchiveInfo.StartPositionAfterHeader, database.ArchiveInfo.DataStartPosition2, dataVector #ifndef _NO_CRYPTO , getTextPassword #endif ); RINOK(result); if (dataVector.Size() == 0) return S_OK; if (dataVector.Size() > 1) throw CInArchiveException(CInArchiveException::kIncorrectHeader); streamSwitch.Remove(); streamSwitch.Set(this, dataVector.Front()); } return ReadHeader(database #ifndef _NO_CRYPTO , getTextPassword #endif );}}}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?