From 762d6a87aaec66b09592496879cb7adab198abf4 Mon Sep 17 00:00:00 2001 From: erysdren Date: Thu, 13 Mar 2025 12:10:33 -0500 Subject: [PATCH 1/2] vpkpp: add support for Volition VPP version 4 --- include/vpkpp/format/VPP.h | 3 ++- src/vpkpp/format/VPP.cpp | 50 +++++++++++++++++++++++++++++++++++--- test/vpkpp.cpp | 16 ++++++++++++ 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/include/vpkpp/format/VPP.h b/include/vpkpp/format/VPP.h index df76ca78..608310dd 100644 --- a/include/vpkpp/format/VPP.h +++ b/include/vpkpp/format/VPP.h @@ -16,7 +16,8 @@ class VPP : public PackFileReadOnly { enum Flags : uint32_t { FLAG_NONE = 0, FLAG_COMPRESSED = 1 << 0, - FLAG_CONDENSED = 1 << 1 + FLAG_CONDENSED = 1 << 1, + FLAG_UNK5 = 1 << 5, // v4.vpp_xbox2 }; /// Open a VPP file diff --git a/src/vpkpp/format/VPP.cpp b/src/vpkpp/format/VPP.cpp index 2058d368..65fd80e7 100644 --- a/src/vpkpp/format/VPP.cpp +++ b/src/vpkpp/format/VPP.cpp @@ -121,7 +121,7 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback callback(entryPath, entry); } } - } else if (version == 3) { + } else if (version == 3 || version == 4) { // Skip unused header data reader.skip_in(64 + 256 + sizeof(uint32_t)); @@ -147,6 +147,11 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Get sizes const auto entryDirectorySize = reader.read(); const auto entryNamesSize = reader.read(); + uint32_t entryExtensionsSize = 0; + + if (version == 4) { + entryExtensionsSize = reader.read(); + } // Check if we have compression const auto entryDataSizeUncompressed = reader.read(); @@ -157,6 +162,10 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback + entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + entryNamesSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryNamesSize); + if (version == 4) { + vpp->entryBaseOffset += entryExtensionsSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryExtensionsSize); + } + // Seek to file directory (alignment boundary) reader.seek_in(VPP_ALIGNMENT); @@ -166,6 +175,10 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Get file name offset const auto entryNameOffset = reader.read(); + uint32_t entryExtensionOffset = 0; + if (version == 4) { + entryExtensionOffset = reader.read(); + } // ?? reader.skip_in(); @@ -174,7 +187,9 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback entry.offset = reader.read(); // ?? - reader.skip_in(); + if (version == 3) { + reader.skip_in(); + } // Get file size entry.length = reader.read(); @@ -190,8 +205,35 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Get file name const auto lastPos = reader.tell_in(); - reader.seek_in(VPP_ALIGNMENT + entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + entryNameOffset); - const auto entryPath = vpp->cleanEntryPath(reader.read_string(entryNamesSize - entryNameOffset)); + + std::string entryPath; + + if (version == 4) { + // Version 4 + reader.seek_in( + VPP_ALIGNMENT + + entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + + entryNameOffset + ); + + std::string entryName = reader.read_string(entryNamesSize - entryNameOffset); + + reader.seek_in( + VPP_ALIGNMENT + + entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + + entryNamesSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryNamesSize) + + entryExtensionOffset + ); + + std::string entryExtension = reader.read_string(entryExtensionsSize - entryExtensionOffset); + + entryPath = vpp->cleanEntryPath(entryName + "." + entryExtension); + } else { + // Version 3 + reader.seek_in(VPP_ALIGNMENT + entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + entryNameOffset); + entryPath = vpp->cleanEntryPath(reader.read_string(entryNamesSize - entryNameOffset)); + } + reader.seek_in_u(lastPos); // Put it in diff --git a/test/vpkpp.cpp b/test/vpkpp.cpp index 6ccbb8f3..2660b628 100644 --- a/test/vpkpp.cpp +++ b/test/vpkpp.cpp @@ -58,3 +58,19 @@ TEST(vpkpp, vpp_v3_big_read) { EXPECT_EQ(vpp->getEntryCount(), 20); EXPECT_TRUE(vpp->hasEntry("pretty.txt")); } + +TEST(vpkpp, vpp_v4_lil_read) { + const auto vpp = PackFile::open(ASSET_ROOT "vpkpp/vpp/v4.vpp_pc"); + ASSERT_TRUE(vpp); + VPKPP_PRINT_ALL_PATHS(vpp); + EXPECT_EQ(vpp->getEntryCount(), 730); + EXPECT_TRUE(vpp->hasEntry("sr2_skybox.hmap_pc")); +} + +TEST(vpkpp, vpp_v4_big_read) { + const auto vpp = PackFile::open(ASSET_ROOT "vpkpp/vpp/v4.vpp_xbox2"); + ASSERT_TRUE(vpp); + VPKPP_PRINT_ALL_PATHS(vpp); + EXPECT_EQ(vpp->getEntryCount(), 118); + EXPECT_TRUE(vpp->hasEntry("activity_level.lua")); +} From c9124d3b6eca6851610eebb2cda88d93785328c3 Mon Sep 17 00:00:00 2001 From: craftablescience Date: Wed, 5 Mar 2025 21:09:27 -0500 Subject: [PATCH 2/2] vpkpp: VPP code doesnt need to use explicit sourcepp namespace --- src/vpkpp/format/VPP.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/vpkpp/format/VPP.cpp b/src/vpkpp/format/VPP.cpp index 65fd80e7..4fa7af59 100644 --- a/src/vpkpp/format/VPP.cpp +++ b/src/vpkpp/format/VPP.cpp @@ -41,12 +41,12 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Get file table offset static constexpr uint32_t headerSize = sizeof(uint32_t) * 4; - reader.seek_in(headerSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, headerSize)); + reader.seek_in(headerSize + math::paddingForAlignment(VPP_ALIGNMENT, headerSize)); // Get base file offset const uint32_t fileTableSize = (60 + sizeof(uint32_t)) * entryCount; - vpp->entryBaseOffset = headerSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, headerSize) - + fileTableSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, fileTableSize); + vpp->entryBaseOffset = headerSize + math::paddingForAlignment(VPP_ALIGNMENT, headerSize) + + fileTableSize + math::paddingForAlignment(VPP_ALIGNMENT, fileTableSize); // Get first file offset uint32_t entryOffset = 0; @@ -63,7 +63,7 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Calculate file offset entry.offset = entryOffset; - entryOffset += entry.length + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entry.length); + entryOffset += entry.length + math::paddingForAlignment(VPP_ALIGNMENT, entry.length); // Put it in vpp->entries.emplace(entryPath, entry); @@ -83,12 +83,12 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Get file table offset static constexpr uint32_t headerSize = sizeof(uint32_t) * 4; - reader.seek_in(headerSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, headerSize)); + reader.seek_in(headerSize + math::paddingForAlignment(VPP_ALIGNMENT, headerSize)); // Get base file offset const uint32_t fileTableSize = (24 + sizeof(uint32_t) * 2) * entryCount; - vpp->entryBaseOffset = headerSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, headerSize) - + fileTableSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, fileTableSize); + vpp->entryBaseOffset = headerSize + math::paddingForAlignment(VPP_ALIGNMENT, headerSize) + + fileTableSize + math::paddingForAlignment(VPP_ALIGNMENT, fileTableSize); // Get first file offset uint32_t entryOffset = 0; @@ -112,7 +112,7 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Calculate file offset entry.offset = entryOffset; - entryOffset += entry.length + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entry.length); + entryOffset += entry.length + math::paddingForAlignment(VPP_ALIGNMENT, entry.length); // Put it in vpp->entries.emplace(entryPath, entry); @@ -159,11 +159,11 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Set base data offset vpp->entryBaseOffset = VPP_ALIGNMENT - + entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) - + entryNamesSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryNamesSize); + + entryDirectorySize + math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + + entryNamesSize + math::paddingForAlignment(VPP_ALIGNMENT, entryNamesSize); if (version == 4) { - vpp->entryBaseOffset += entryExtensionsSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryExtensionsSize); + vpp->entryBaseOffset += entryExtensionsSize + math::paddingForAlignment(VPP_ALIGNMENT, entryExtensionsSize); } // Seek to file directory (alignment boundary) @@ -212,7 +212,7 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback // Version 4 reader.seek_in( VPP_ALIGNMENT + - entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + + entryDirectorySize + math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + entryNameOffset ); @@ -220,8 +220,8 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback reader.seek_in( VPP_ALIGNMENT + - entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + - entryNamesSize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryNamesSize) + + entryDirectorySize + math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + + entryNamesSize + math::paddingForAlignment(VPP_ALIGNMENT, entryNamesSize) + entryExtensionOffset ); @@ -230,7 +230,7 @@ std::unique_ptr VPP::open(const std::string& path, const EntryCallback entryPath = vpp->cleanEntryPath(entryName + "." + entryExtension); } else { // Version 3 - reader.seek_in(VPP_ALIGNMENT + entryDirectorySize + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + entryNameOffset); + reader.seek_in(VPP_ALIGNMENT + entryDirectorySize + math::paddingForAlignment(VPP_ALIGNMENT, entryDirectorySize) + entryNameOffset); entryPath = vpp->cleanEntryPath(reader.read_string(entryNamesSize - entryNameOffset)); }