From f16d538aeee41b4ff5ae6a1adfb097b8744ed81d Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 12 Oct 2022 23:39:26 +0200 Subject: [PATCH] CPackedStore: light optimizations * Don't call copy constructor on entry blocks when building the directory file. * Don't call copy constructor for string when we don't want to sanitize the directory file name. --- r5dev/vpklib/packedstore.cpp | 66 ++++++++++++++++++------------------ r5dev/vpklib/packedstore.h | 57 ++++++++++++++++++------------- 2 files changed, 67 insertions(+), 56 deletions(-) diff --git a/r5dev/vpklib/packedstore.cpp b/r5dev/vpklib/packedstore.cpp index 7d69bfc4..16d33d66 100644 --- a/r5dev/vpklib/packedstore.cpp +++ b/r5dev/vpklib/packedstore.cpp @@ -1,11 +1,15 @@ -/******************************************************************* -* ██████╗ ██╗ ██╗ ██╗██████╗ ██╗ ██╗ ██╗ ██╗██████╗ * -* ██╔══██╗███║ ██║ ██║██╔══██╗██║ ██╔╝ ██║ ██║██╔══██╗ * -* ██████╔╝╚██║ ██║ ██║██████╔╝█████╔╝ ██║ ██║██████╔╝ * -* ██╔══██╗ ██║ ╚██╗ ██╔╝██╔═══╝ ██╔═██╗ ██║ ██║██╔══██╗ * -* ██║ ██║ ██║ ╚████╔╝ ██║ ██║ ██╗ ███████╗██║██████╔╝ * -* ╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝╚═════╝ * -*******************************************************************/ +//=============================================================================// +// +// Purpose: Valve Pak utility class. +// +//=============================================================================// +// packedstore.cpp +// +// Note: VPK's are created in pairs of a directory file and block archive(s). +// - _.bsp.pak000_dir.vpk --> directory file. +// - _.bsp.pak000_.vpk --> block archive. +// +///////////////////////////////////////////////////////////////////////////////// #include "core/stdafx.h" #include "tier1/cvar.h" #include "mathlib/adler32.h" @@ -48,51 +52,48 @@ void CPackedStore::InitLzDecompParams(void) // bSanitizeName - retrieve the directory file name from block name // Output : VPKDir_t //----------------------------------------------------------------------------- -VPKDir_t CPackedStore::GetDirectoryFile(string svPackDirFile, bool bSanitizeName) const +VPKDir_t CPackedStore::GetDirectoryFile(const string& svPackDirFile, bool bSanitizeName) const { - /*| PACKDIRFILE |||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ - std::smatch smRegexMatches; - if (!bSanitizeName) return VPKDir_t(svPackDirFile); + std::smatch smRegexMatches; std::regex_search(svPackDirFile, smRegexMatches, BLOCK_REGEX); + if (smRegexMatches.empty()) return VPKDir_t(svPackDirFile); - StringReplace(svPackDirFile, smRegexMatches[0], "pak000_dir"); + string svSanitizedName = svPackDirFile; + StringReplace(svSanitizedName, smRegexMatches[0], "pak000_dir"); bool bHasLocale = false; - string svPackDirPrefix; - - for (size_t i = 0, nl = DIR_LOCALE.size(); i < nl; i++) + for (const string& svLocale : DIR_LOCALE) { - const string& svLocale = DIR_LOCALE[i]; - if (svPackDirFile.find(svLocale) != string::npos) + if (svSanitizedName.find(svLocale) != string::npos) { bHasLocale = true; break; } } - if (!bHasLocale) + if (!bHasLocale) // Only sanitize if no locale was provided. { + string svPackDirPrefix; svPackDirPrefix.append(DIR_LOCALE[0]); - for (size_t i = 0, nc = DIR_CONTEXT.size(); i < nc; i++) + for (const string& svContext : DIR_CONTEXT) { - const string& svContext = DIR_CONTEXT[i]; - if (svPackDirFile.find(svContext) != string::npos) + if (svSanitizedName.find(svContext) != string::npos) { svPackDirPrefix.append(svContext); - StringReplace(svPackDirFile, svContext, svPackDirPrefix); + StringReplace(svSanitizedName, svContext, svPackDirPrefix); break; } } } - return VPKDir_t(svPackDirFile); + return VPKDir_t(svSanitizedName); } //----------------------------------------------------------------------------- @@ -103,7 +104,6 @@ VPKDir_t CPackedStore::GetDirectoryFile(string svPackDirFile, bool bSanitizeName //----------------------------------------------------------------------------- string CPackedStore::GetPackFile(const string& svPackDirFile, uint16_t iArchiveIndex) const { - /*| ARCHIVES ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ string svPackChunkFile = StripLocalePrefix(svPackDirFile); ostringstream oss; @@ -143,7 +143,6 @@ lzham_compress_level CPackedStore::GetCompressionLevel(void) const //----------------------------------------------------------------------------- vector CPackedStore::GetEntryBlocks(CIOStream* pReader) const { - /*| ENTRYBLOCKS |||||||||||||||||||||||||||||||||||||||||||||||||||||||||*/ string svName, svPath, svExtension; vector vBlocks; while (!(svExtension = pReader->ReadString()).empty()) @@ -402,12 +401,13 @@ void CPackedStore::BuildManifest(const vector& vBlock, const st for (const VPKEntryBlock_t& vEntry : vBlock) { + const VPKChunkDescriptor_t& vDescriptor = vEntry.m_vChunks[0]; jEntry[vEntry.m_svEntryPath] = { { "preloadSize", vEntry.m_iPreloadSize }, - { "loadFlags", vEntry.m_vChunks[0].m_nLoadFlags }, - { "textureFlags", vEntry.m_vChunks[0].m_nTextureFlags }, - { "useCompression", vEntry.m_vChunks[0].m_nCompressedSize != vEntry.m_vChunks[0].m_nUncompressedSize }, + { "loadFlags", vDescriptor.m_nLoadFlags }, + { "textureFlags", vDescriptor.m_nTextureFlags }, + { "useCompression", vDescriptor.m_nCompressedSize != vDescriptor.m_nUncompressedSize }, { "useDataSharing", true } }; } @@ -594,8 +594,8 @@ void CPackedStore::UnpackAll(const VPKDir_t& vDir, const string& svPathOut) for (size_t i = 0, fs = vDir.m_vPackFile.size(); i < fs; i++) { - fs::path fspVpkPath(vDir.m_svDirPath); - string svPath = fspVpkPath.parent_path().u8string() + '\\' + vDir.m_vPackFile[i]; + const fs::path fspVpkPath(vDir.m_svDirPath); + const string svPath = fspVpkPath.parent_path().u8string() + '\\' + vDir.m_vPackFile[i]; CIOStream iStream(svPath, CIOStream::Mode_t::READ); // Create stream to read from each archive. for (size_t j = 0, es = vDir.m_vEntryBlocks.size(); j < es; j++) @@ -607,7 +607,7 @@ void CPackedStore::UnpackAll(const VPKDir_t& vDir, const string& svPathOut) } else // Chunk belongs to this block. { - string svFilePath = CreateDirectories(svPathOut + vBlock.m_svEntryPath); + const string svFilePath = CreateDirectories(svPathOut + vBlock.m_svEntryPath); CIOStream oStream(svFilePath, CIOStream::Mode_t::WRITE); if (!oStream.IsWritable()) @@ -802,7 +802,7 @@ void VPKDir_t::Build(const string& svDirectoryFile, const vector(this->m_vHeader.m_nDirectorySize); writer.Write(this->m_vHeader.m_nSignatureSize); - for (VPKEntryBlock_t vBlock : vEntryBlocks) + for (const VPKEntryBlock_t& vBlock : vEntryBlocks) { string svExtension = GetExtension(vBlock.m_svEntryPath); string svFilePath = RemoveFileName(vBlock.m_svEntryPath); diff --git a/r5dev/vpklib/packedstore.h b/r5dev/vpklib/packedstore.h index 9a0bf57d..73e3a0bf 100644 --- a/r5dev/vpklib/packedstore.h +++ b/r5dev/vpklib/packedstore.h @@ -1,4 +1,13 @@ -#pragma once +#ifndef PACKEDSTORE_H +#define PACKEDSTORE_H +/******************************************************************* +* ██████╗ ██╗ ██╗ ██╗██████╗ ██╗ ██╗ ██╗ ██╗██████╗ * +* ██╔══██╗███║ ██║ ██║██╔══██╗██║ ██╔╝ ██║ ██║██╔══██╗ * +* ██████╔╝╚██║ ██║ ██║██████╔╝█████╔╝ ██║ ██║██████╔╝ * +* ██╔══██╗ ██║ ╚██╗ ██╔╝██╔═══╝ ██╔═██╗ ██║ ██║██╔══██╗ * +* ██║ ██║ ██║ ╚████╔╝ ██║ ██║ ██╗ ███████╗██║██████╔╝ * +* ╚═╝ ╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝╚═════╝ * +*******************************************************************/ #include "public/utility/binstream.h" #include "thirdparty/lzham/include/lzham.h" @@ -83,11 +92,11 @@ struct VPKData_t struct VPKChunkDescriptor_t { - uint32_t m_nLoadFlags {}; // Load flags. - uint16_t m_nTextureFlags {}; // Texture flags (only used if the entry is a vtf). - uint64_t m_nArchiveOffset {}; // Offset in archive. - uint64_t m_nCompressedSize {}; // Compressed size of chunk. - uint64_t m_nUncompressedSize{}; // Uncompressed size of chunk. + uint32_t m_nLoadFlags; // Load flags. + uint16_t m_nTextureFlags; // Texture flags (only used if the entry is a vtf). + uint64_t m_nArchiveOffset; // Offset in archive. + uint64_t m_nCompressedSize; // Compressed size of chunk. + uint64_t m_nUncompressedSize; // Uncompressed size of chunk. bool m_bIsCompressed = false; VPKChunkDescriptor_t(){}; @@ -97,11 +106,11 @@ struct VPKChunkDescriptor_t struct VPKEntryBlock_t { - uint32_t m_nFileCRC {}; // Crc32 for the uncompressed entry. - uint16_t m_iPreloadSize {}; // Preload bytes. - uint16_t m_iPackFileIndex{}; // Index of the pack file that contains this entry. - vector m_vChunks {}; // Vector of all the chunks of a given entry (chunks have a size limit of 1 MiB, anything over this limit is fragmented into smaller chunks). - string m_svEntryPath {}; // Path to entry within vpk. + uint32_t m_nFileCRC; // Crc32 for the uncompressed entry. + uint16_t m_iPreloadSize; // Preload bytes. + uint16_t m_iPackFileIndex; // Index of the pack file that contains this entry. + vector m_vChunks; // Vector of all the chunks of a given entry (chunks have a size limit of 1 MiB, anything over this limit is fragmented into smaller chunks). + string m_svEntryPath; // Path to entry within vpk. VPKEntryBlock_t(CIOStream* pReader, string svEntryPath); VPKEntryBlock_t(const vector& vData, int64_t nOffset, uint16_t nPreloadData, uint16_t nArchiveIndex, uint32_t nEntryFlags, uint16_t nTextureFlags, const string& svEntryPath); @@ -109,21 +118,21 @@ struct VPKEntryBlock_t struct VPKDirHeader_t { - uint32_t m_nHeaderMarker {}; // File magic. - uint16_t m_nMajorVersion {}; // Vpk major version. - uint16_t m_nMinorVersion {}; // Vpk minor version. - uint32_t m_nDirectorySize{}; // Directory tree size. - uint32_t m_nSignatureSize{}; // Directory signature. + uint32_t m_nHeaderMarker; // File magic. + uint16_t m_nMajorVersion; // Vpk major version. + uint16_t m_nMinorVersion; // Vpk minor version. + uint32_t m_nDirectorySize; // Directory tree size. + uint32_t m_nSignatureSize; // Directory signature. }; struct VPKDir_t { - VPKDirHeader_t m_vHeader {}; // Dir header. - uint32_t m_nFileDataSize {}; // File data section size. - vector m_vEntryBlocks {}; // Vector of entry blocks. - uint16_t m_iPackFileCount{}; // Highest archive index (archive count-1). - vector m_vPackFile {}; // Vector of archive file names. - string m_svDirPath {}; // Path to vpk_dir file. + VPKDirHeader_t m_vHeader; // Dir header. + uint32_t m_nFileDataSize; // File data section size. + vector m_vEntryBlocks; // Vector of entry blocks. + uint16_t m_iPackFileCount; // Highest archive index (archive count-1). + vector m_vPackFile; // Vector of archive file names. + string m_svDirPath; // Path to vpk_dir file. VPKDir_t(const string& svPath); VPKDir_t() { m_vHeader.m_nHeaderMarker = VPK_HEADER_MARKER; m_vHeader.m_nMajorVersion = VPK_MAJOR_VERSION; m_vHeader.m_nMinorVersion = VPK_MINOR_VERSION; }; @@ -143,7 +152,7 @@ public: void InitLzCompParams(void); void InitLzDecompParams(void); - VPKDir_t GetDirectoryFile(string svDirectoryFile, bool bSanitizeName) const; + VPKDir_t GetDirectoryFile(const string& svDirectoryFile, bool bSanitizeName) const; string GetPackFile(const string& svPackDirFile, uint16_t iArchiveIndex) const; lzham_compress_level GetCompressionLevel(void) const; @@ -183,3 +192,5 @@ private: }; /////////////////////////////////////////////////////////////////////////////// extern CPackedStore* g_pPackedStore; + +#endif // PACKEDSTORE_H \ No newline at end of file