From 2bc570800ba714c5e5c50368c6e07847ebd674da Mon Sep 17 00:00:00 2001
From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com>
Date: Wed, 23 Nov 2022 12:27:57 +0100
Subject: [PATCH] Split 'VPKDir_t::Build' into multiple methods

Each process of writing out a VPK directory is now within its own method.
---
 r5dev/vpklib/packedstore.cpp | 178 +++++++++++++++++++++--------------
 r5dev/vpklib/packedstore.h   |   7 +-
 2 files changed, 114 insertions(+), 71 deletions(-)

diff --git a/r5dev/vpklib/packedstore.cpp b/r5dev/vpklib/packedstore.cpp
index 6e855525..e66aeb1f 100644
--- a/r5dev/vpklib/packedstore.cpp
+++ b/r5dev/vpklib/packedstore.cpp
@@ -609,7 +609,7 @@ void CPackedStore::PackWorkspace(const VPKPair_t& vPair, const string& svWorkspa
 	memset(s_EntryBuf, '\0', sizeof(s_EntryBuf));
 
 	VPKDir_t vDir = VPKDir_t();
-	vDir.Build(svBuildPath + vPair.m_svDirectoryName, vEntryBlocks);
+	vDir.BuildDirectoryFile(svBuildPath + vPair.m_svDirectoryName, vEntryBlocks);
 }
 
 //-----------------------------------------------------------------------------
@@ -862,28 +862,92 @@ VPKDir_t::VPKDir_t(const string& svPath)
 }
 
 //-----------------------------------------------------------------------------
-// Purpose: builds the vpk directory file
-// Input  : &svDirectoryFile - 
-//          &vEntryBlocks - 
+// Purpose: writes the vpk directory header
+// Input  : pDirectoryFile - 
 //-----------------------------------------------------------------------------
-void VPKDir_t::Build(const string& svDirectoryFile, const vector<VPKEntryBlock_t>& vEntryBlocks)
+void VPKDir_t::WriteHeader(FileHandle_t pDirectoryFile) const
 {
-	FileHandle_t hDirectoryFile = FileSystem()->Open(svDirectoryFile.c_str(), "wb", "GAME");
-	if (!hDirectoryFile)
-	{
-		Error(eDLL_T::FS, NO_ERROR, "%s - Unable to write to '%s' (read-only?)\n", __FUNCTION__, svDirectoryFile.c_str());
-		return;
-	}
+	FileSystem()->Write(&m_vHeader.m_nHeaderMarker, sizeof(uint32_t), pDirectoryFile);
+	FileSystem()->Write(&m_vHeader.m_nMajorVersion, sizeof(uint16_t), pDirectoryFile);
+	FileSystem()->Write(&m_vHeader.m_nMinorVersion, sizeof(uint16_t), pDirectoryFile);
+	FileSystem()->Write(&m_vHeader.m_nDirectorySize, sizeof(uint32_t), pDirectoryFile);
+	FileSystem()->Write(&m_vHeader.m_nSignatureSize, sizeof(uint32_t), pDirectoryFile);
+}
 
-	auto vMap = std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>();
+//-----------------------------------------------------------------------------
+// Purpose: writes the directory tree size
+// Input  : &vEntryBlocks - 
+//-----------------------------------------------------------------------------
+void VPKDir_t::WriteTreeSize(FileHandle_t pDirectoryFile) const
+{
+	FileSystem()->Seek(pDirectoryFile, offsetof(VPKDir_t, m_vHeader.m_nDirectorySize), FileSystemSeek_t::FILESYSTEM_SEEK_HEAD);
+	FileSystem()->Write(&m_vHeader.m_nDirectorySize, sizeof(uint32_t), pDirectoryFile);
+	FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint32_t), pDirectoryFile);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: writes the vpk chunk descriptors
+// Input  : pDirectoryFile - 
+//			&vMap - 
+// Output : number of descriptors written
+//-----------------------------------------------------------------------------
+uint64_t VPKDir_t::WriteDescriptor(FileHandle_t pDirectoryFile, std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>& vMap) const
+{
 	uint64_t nDescriptors = NULL;
 
-	FileSystem()->Write(&m_vHeader.m_nHeaderMarker, sizeof(uint32_t), hDirectoryFile);
-	FileSystem()->Write(&m_vHeader.m_nMajorVersion, sizeof(uint16_t), hDirectoryFile);
-	FileSystem()->Write(&m_vHeader.m_nMinorVersion, sizeof(uint16_t), hDirectoryFile);
-	FileSystem()->Write(&m_vHeader.m_nDirectorySize, sizeof(uint32_t), hDirectoryFile);
-	FileSystem()->Write(&m_vHeader.m_nSignatureSize, sizeof(uint32_t), hDirectoryFile);
+	for (auto& iKeyValue : vMap)
+	{
+		FileSystem()->Write(iKeyValue.first.c_str(), (iKeyValue.first.length() + 1), pDirectoryFile);
+		for (auto& jKeyValue : iKeyValue.second)
+		{
+			FileSystem()->Write(jKeyValue.first.c_str(), (jKeyValue.first.length() + 1), pDirectoryFile);
+			for (auto& vEntry : jKeyValue.second)
+			{
+				string pszEntryPath = GetFileName(vEntry.m_svEntryPath, true);
+				FileSystem()->Write(pszEntryPath.c_str(), (pszEntryPath.length() + 1), pDirectoryFile);
 
+				FileSystem()->Write(&vEntry.m_nFileCRC, sizeof(uint32_t), pDirectoryFile);
+				FileSystem()->Write(&vEntry.m_iPreloadSize, sizeof(uint16_t), pDirectoryFile);
+				FileSystem()->Write(&vEntry.m_iPackFileIndex, sizeof(uint16_t), pDirectoryFile);
+
+				for (size_t i = 0, nc = vEntry.m_vFragments.size(); i < nc; i++)
+				{
+					/*Write chunk descriptor*/
+					const VPKChunkDescriptor_t* pDescriptor = &vEntry.m_vFragments[i];
+
+					FileSystem()->Write(&pDescriptor->m_nLoadFlags, sizeof(uint32_t), pDirectoryFile);
+					FileSystem()->Write(&pDescriptor->m_nTextureFlags, sizeof(uint16_t), pDirectoryFile);
+					FileSystem()->Write(&pDescriptor->m_nPackFileOffset, sizeof(uint64_t), pDirectoryFile);
+					FileSystem()->Write(&pDescriptor->m_nCompressedSize, sizeof(uint64_t), pDirectoryFile);
+					FileSystem()->Write(&pDescriptor->m_nUncompressedSize, sizeof(uint64_t), pDirectoryFile);
+
+					if (i != (nc - 1))
+					{
+						FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint16_t), pDirectoryFile);
+					}
+					else // Mark end of entry.
+					{
+						FileSystem()->Write(&PACKFILEINDEX_END, sizeof(uint16_t), pDirectoryFile);
+					}
+					nDescriptors++;
+				}
+			}
+			FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), pDirectoryFile);
+		}
+		FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), pDirectoryFile);
+	}
+	FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), pDirectoryFile);
+
+	return nDescriptors;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: builds the vpk directory tree
+// Input  : &vEntryBlocks - 
+//          &vMap - 
+//-----------------------------------------------------------------------------
+void VPKDir_t::BuildDirectoryTree(const vector<VPKEntryBlock_t>& vEntryBlocks, std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>& vMap) const
+{
 	for (const VPKEntryBlock_t& vBlock : vEntryBlocks)
 	{
 		string svExtension = GetExtension(vBlock.m_svEntryPath);
@@ -903,61 +967,35 @@ void VPKDir_t::Build(const string& svDirectoryFile, const vector<VPKEntryBlock_t
 		}
 		vMap[svExtension][svFilePath].push_back(vBlock);
 	}
-
-	for (auto& iKeyValue : vMap)
-	{
-		FileSystem()->Write(iKeyValue.first.c_str(), (iKeyValue.first.length() + 1), hDirectoryFile);
-		for (auto& jKeyValue : iKeyValue.second)
-		{
-			FileSystem()->Write(jKeyValue.first.c_str(), (jKeyValue.first.length() + 1), hDirectoryFile);
-			for (auto& vEntry : jKeyValue.second)
-			{
-				string pszEntryPath = GetFileName(vEntry.m_svEntryPath, true);
-				FileSystem()->Write(pszEntryPath.c_str(), (pszEntryPath.length() + 1), hDirectoryFile);
-
-				FileSystem()->Write(&vEntry.m_nFileCRC, sizeof(uint32_t), hDirectoryFile);
-				FileSystem()->Write(&vEntry.m_iPreloadSize, sizeof(uint16_t), hDirectoryFile);
-				FileSystem()->Write(&vEntry.m_iPackFileIndex, sizeof(uint16_t), hDirectoryFile);
-
-				for (size_t i = 0, nc = vEntry.m_vFragments.size(); i < nc; i++)
-				{
-					/*Write chunk descriptor*/
-					const VPKChunkDescriptor_t* pDescriptor = &vEntry.m_vFragments[i];
-
-					FileSystem()->Write(&pDescriptor->m_nLoadFlags, sizeof(uint32_t), hDirectoryFile);
-					FileSystem()->Write(&pDescriptor->m_nTextureFlags, sizeof(uint16_t), hDirectoryFile);
-					FileSystem()->Write(&pDescriptor->m_nPackFileOffset, sizeof(uint64_t), hDirectoryFile);
-					FileSystem()->Write(&pDescriptor->m_nCompressedSize, sizeof(uint64_t), hDirectoryFile);
-					FileSystem()->Write(&pDescriptor->m_nUncompressedSize, sizeof(uint64_t), hDirectoryFile);
-
-					if (i != (nc - 1))
-					{
-						FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint16_t), hDirectoryFile);
-					}
-					else // Mark end of entry.
-					{
-						FileSystem()->Write(&PACKFILEINDEX_END, sizeof(uint16_t), hDirectoryFile);
-					}
-					nDescriptors++;
-				}
-			}
-			FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), hDirectoryFile);
-		}
-		FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), hDirectoryFile);
-	}
-	FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint8_t), hDirectoryFile);
-	m_vHeader.m_nDirectorySize = static_cast<uint32_t>(FileSystem()->Tell(hDirectoryFile) - sizeof(VPKDirHeader_t));
-
-	FileSystem()->Seek(hDirectoryFile, offsetof(VPKDir_t, m_vHeader.m_nDirectorySize), FileSystemSeek_t::FILESYSTEM_SEEK_HEAD);
-	FileSystem()->Write(&m_vHeader.m_nDirectorySize, sizeof(uint32_t), hDirectoryFile);
-	FileSystem()->Write(&PACKFILEINDEX_SEP, sizeof(uint32_t), hDirectoryFile);
-
-	FileSystem()->Close(hDirectoryFile);
-
-	DevMsg(eDLL_T::FS, "*** Build directory totaling '%zu' bytes with '%zu' entries and '%zu' descriptors\n", 
-		size_t(sizeof(VPKDirHeader_t) + m_vHeader.m_nDirectorySize), vEntryBlocks.size(), nDescriptors);
 }
 
+//-----------------------------------------------------------------------------
+// Purpose: builds the vpk directory file
+// Input  : &svDirectoryFile - 
+//          &vEntryBlocks - 
+//-----------------------------------------------------------------------------
+void VPKDir_t::BuildDirectoryFile(const string& svDirectoryFile, const vector<VPKEntryBlock_t>& vEntryBlocks)
+{
+	FileHandle_t pDirectoryFile = FileSystem()->Open(svDirectoryFile.c_str(), "wb", "GAME");
+	if (!pDirectoryFile)
+	{
+		Error(eDLL_T::FS, NO_ERROR, "%s - Unable to write to '%s' (read-only?)\n", __FUNCTION__, svDirectoryFile.c_str());
+		return;
+	}
+
+	auto vMap = std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>();
+	BuildDirectoryTree(vEntryBlocks, vMap);
+
+	WriteHeader(pDirectoryFile);
+	uint64_t nDescriptors = WriteDescriptor(pDirectoryFile, vMap);
+
+	m_vHeader.m_nDirectorySize = static_cast<uint32_t>(FileSystem()->Tell(pDirectoryFile) - sizeof(VPKDirHeader_t));
+	WriteTreeSize(pDirectoryFile);
+
+	FileSystem()->Close(pDirectoryFile);
+	DevMsg(eDLL_T::FS, "*** Build directory totaling '%zu' bytes with '%zu' entries and '%zu' descriptors\n",
+		size_t(sizeof(VPKDirHeader_t) + m_vHeader.m_nDirectorySize), vEntryBlocks.size(), nDescriptors);
+}
 //-----------------------------------------------------------------------------
 // Singleton
 //-----------------------------------------------------------------------------
diff --git a/r5dev/vpklib/packedstore.h b/r5dev/vpklib/packedstore.h
index 8c5b58fd..6c58281d 100644
--- a/r5dev/vpklib/packedstore.h
+++ b/r5dev/vpklib/packedstore.h
@@ -106,7 +106,12 @@ struct VPKDir_t
 	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; };
 
-	void Build(const string& svDirectoryFile, const vector<VPKEntryBlock_t>& vEntryBlocks);
+	void WriteHeader(FileHandle_t pDirectoryFile) const;
+	void WriteTreeSize(FileHandle_t pDirectoryFile) const;
+	uint64_t WriteDescriptor(FileHandle_t pDirectoryFile, std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>& vMap) const;
+
+	void BuildDirectoryTree(const vector<VPKEntryBlock_t>& vEntryBlocks, std::map<string, std::map<string, std::list<VPKEntryBlock_t>>>& vMap) const;
+	void BuildDirectoryFile(const string& svDirectoryFile, const vector<VPKEntryBlock_t>& vEntryBlocks);
 };
 
 struct VPKPair_t