Skip to content

Commit 1bd3ded

Browse files
committed
vpkpp: Volition VPP version 1 support
1 parent f877165 commit 1bd3ded

File tree

4 files changed

+186
-39
lines changed

4 files changed

+186
-39
lines changed

include/vpkpp/format/VPP.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#pragma once
2+
3+
#include <sourcepp/parser/Binary.h>
4+
5+
#include "../PackFile.h"
6+
7+
namespace vpkpp {
8+
9+
constexpr uint32_t VPP_SIGNATURE_LIL = 0x51890ace;
10+
constexpr uint32_t VPP_SIGNATURE_BIG = 0xce0a8951;
11+
constexpr uint32_t VPP_VERSION_MIN = 1;
12+
constexpr uint32_t VPP_VERSION_MAX = 1;
13+
constexpr uint32_t VPP_ALIGNMENT = 2048;
14+
constexpr std::string_view VPP_EXTENSION = ".vpp";
15+
16+
class VPP : public PackFileReadOnly {
17+
public:
18+
/// Open a VPP file
19+
[[nodiscard]] static std::unique_ptr<PackFile> open(const std::string& path, const EntryCallback& callback = nullptr);
20+
21+
static constexpr inline std::string_view GUID = "C47C5C4D88AE4032967F8CDC93D6D2E1";
22+
23+
[[nodiscard]] constexpr std::string_view getGUID() const override {
24+
return VPP::GUID;
25+
}
26+
27+
[[nodiscard]] constexpr bool isCaseSensitive() const override {
28+
return true;
29+
}
30+
31+
[[nodiscard]] std::optional<std::vector<std::byte>> readEntry(const std::string& path_) const override;
32+
33+
[[nodiscard]] Attribute getSupportedEntryAttributes() const override;
34+
35+
protected:
36+
using PackFileReadOnly::PackFileReadOnly;
37+
38+
private:
39+
VPKPP_REGISTER_PACKFILE_OPEN(VPP_EXTENSION, &VPP::open);
40+
};
41+
42+
} // namespace vpkpp

include/vpkpp/vpkpp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "format/PCK.h"
1616
#include "format/VPK.h"
1717
#include "format/VPK_VTMB.h"
18+
#include "format/VPP.h"
1819
#include "format/WAD3.h"
1920
#include "format/ZIP.h"
2021
#include "Attribute.h"

src/vpkpp/_vpkpp.cmake

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,41 @@
1-
add_pretty_parser(vpkpp
2-
DEPS libzstd_static miniz MINIZIP::minizip sourcepp_crypto sourcepp_parser sourcepp::kvpp
3-
DEPS_PUBLIC tsl::hat_trie
4-
PRECOMPILED_HEADERS
5-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/FPX.h"
6-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/GCF.h"
7-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/GMA.h"
8-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/OL.h"
9-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/OO7.h"
10-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/ORE.h"
11-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/PAK.h"
12-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/PCK.h"
13-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/VPK.h"
14-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/VPK_VTMB.h"
15-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/WAD3.h"
16-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/ZIP.h"
17-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/Attribute.h"
18-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/Entry.h"
19-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/Options.h"
20-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/PackFile.h"
21-
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/vpkpp.h"
22-
SOURCES
23-
"${CMAKE_CURRENT_LIST_DIR}/format/FPX.cpp"
24-
"${CMAKE_CURRENT_LIST_DIR}/format/GCF.cpp"
25-
"${CMAKE_CURRENT_LIST_DIR}/format/GMA.cpp"
26-
"${CMAKE_CURRENT_LIST_DIR}/format/OL.cpp"
27-
"${CMAKE_CURRENT_LIST_DIR}/format/OO7.cpp"
28-
"${CMAKE_CURRENT_LIST_DIR}/format/ORE.cpp"
29-
"${CMAKE_CURRENT_LIST_DIR}/format/PAK.cpp"
30-
"${CMAKE_CURRENT_LIST_DIR}/format/PCK.cpp"
31-
"${CMAKE_CURRENT_LIST_DIR}/format/VPK.cpp"
32-
"${CMAKE_CURRENT_LIST_DIR}/format/VPK_VTMB.cpp"
33-
"${CMAKE_CURRENT_LIST_DIR}/format/WAD3.cpp"
34-
"${CMAKE_CURRENT_LIST_DIR}/format/ZIP.cpp"
35-
"${CMAKE_CURRENT_LIST_DIR}/PackFile.cpp")
36-
37-
if(SOURCEPP_VPKPP_SUPPORT_VPK_V54)
38-
target_compile_definitions(sourcepp_vpkpp PRIVATE VPKPP_SUPPORT_VPK_V54)
39-
endif()
1+
add_pretty_parser(vpkpp
2+
DEPS libzstd_static miniz MINIZIP::minizip sourcepp_crypto sourcepp_parser sourcepp::kvpp
3+
DEPS_PUBLIC tsl::hat_trie
4+
PRECOMPILED_HEADERS
5+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/FPX.h"
6+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/GCF.h"
7+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/GMA.h"
8+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/OL.h"
9+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/OO7.h"
10+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/ORE.h"
11+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/PAK.h"
12+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/PCK.h"
13+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/VPK.h"
14+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/VPK_VTMB.h"
15+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/VPP.h"
16+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/WAD3.h"
17+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/format/ZIP.h"
18+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/Attribute.h"
19+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/Entry.h"
20+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/Options.h"
21+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/PackFile.h"
22+
"${CMAKE_CURRENT_SOURCE_DIR}/include/vpkpp/vpkpp.h"
23+
SOURCES
24+
"${CMAKE_CURRENT_LIST_DIR}/format/FPX.cpp"
25+
"${CMAKE_CURRENT_LIST_DIR}/format/GCF.cpp"
26+
"${CMAKE_CURRENT_LIST_DIR}/format/GMA.cpp"
27+
"${CMAKE_CURRENT_LIST_DIR}/format/OL.cpp"
28+
"${CMAKE_CURRENT_LIST_DIR}/format/OO7.cpp"
29+
"${CMAKE_CURRENT_LIST_DIR}/format/ORE.cpp"
30+
"${CMAKE_CURRENT_LIST_DIR}/format/PAK.cpp"
31+
"${CMAKE_CURRENT_LIST_DIR}/format/PCK.cpp"
32+
"${CMAKE_CURRENT_LIST_DIR}/format/VPK.cpp"
33+
"${CMAKE_CURRENT_LIST_DIR}/format/VPK_VTMB.cpp"
34+
"${CMAKE_CURRENT_LIST_DIR}/format/VPP.cpp"
35+
"${CMAKE_CURRENT_LIST_DIR}/format/WAD3.cpp"
36+
"${CMAKE_CURRENT_LIST_DIR}/format/ZIP.cpp"
37+
"${CMAKE_CURRENT_LIST_DIR}/PackFile.cpp")
38+
39+
if(SOURCEPP_VPKPP_SUPPORT_VPK_V54)
40+
target_compile_definitions(sourcepp_vpkpp PRIVATE VPKPP_SUPPORT_VPK_V54)
41+
endif()

src/vpkpp/format/VPP.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#include <vpkpp/format/VPP.h>
2+
3+
#include <filesystem>
4+
5+
#include <FileStream.h>
6+
7+
using namespace sourcepp;
8+
using namespace vpkpp;
9+
10+
std::unique_ptr<PackFile> VPP::open(const std::string& path, const EntryCallback& callback) {
11+
if (!std::filesystem::exists(path)) {
12+
// File does not exist
13+
return nullptr;
14+
}
15+
16+
auto* vpp = new VPP{path};
17+
auto packFile = std::unique_ptr<PackFile>(vpp);
18+
19+
FileStream reader{vpp->fullFilePath};
20+
reader.seek_in(0);
21+
22+
// Verify signature
23+
auto signature = reader.read<uint32_t>();
24+
if (signature == VPP_SIGNATURE_BIG) {
25+
reader.set_big_endian(true);
26+
} else if (signature != VPP_SIGNATURE_LIL) {
27+
return nullptr;
28+
}
29+
30+
// Verify version
31+
auto version = reader.read<uint32_t>();
32+
if (version < VPP_VERSION_MIN || version > VPP_VERSION_MAX) {
33+
return nullptr;
34+
}
35+
36+
// Create entries
37+
if (version == 1) {
38+
// Get header fields
39+
auto num_files = reader.read<uint32_t>();
40+
auto len_vpp = reader.read<uint32_t>();
41+
42+
// Verify file size
43+
if (len_vpp != std::filesystem::file_size(path)) {
44+
return nullptr;
45+
}
46+
47+
// Seek past header to 2048 byte boundary
48+
reader.seek_in(VPP_ALIGNMENT);
49+
50+
// Get first file offset
51+
// 64 is the byte size of each file directory entry
52+
uint32_t entryOffset = VPP_ALIGNMENT + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, 64 * num_files);
53+
54+
// Read file entries
55+
for (uint32_t i = 0; i < num_files; i++) {
56+
Entry entry = createNewEntry();
57+
58+
// Get file path
59+
const auto entryPath = vpp->cleanEntryPath(reader.read_string(60));
60+
61+
// Get file size
62+
entry.length = reader.read<uint32_t>();
63+
64+
// Calculate file offset
65+
entry.offset = entryOffset;
66+
entryOffset += entry.length + sourcepp::math::paddingForAlignment(VPP_ALIGNMENT, entry.length);
67+
68+
// Put it in
69+
vpp->entries.emplace(entryPath, entry);
70+
71+
if (callback) {
72+
callback(entryPath, entry);
73+
}
74+
}
75+
}
76+
77+
return packFile;
78+
}
79+
80+
std::optional<std::vector<std::byte>> VPP::readEntry(const std::string& path_) const {
81+
auto path = this->cleanEntryPath(path_);
82+
auto entry = this->findEntry(path);
83+
if (!entry) {
84+
return std::nullopt;
85+
}
86+
if (entry->unbaked) {
87+
return readUnbakedEntry(*entry);
88+
}
89+
90+
// It's baked into the file on disk
91+
FileStream stream{this->fullFilePath};
92+
if (!stream) {
93+
return std::nullopt;
94+
}
95+
stream.seek_in_u(entry->offset);
96+
return stream.read_bytes(entry->length);
97+
}
98+
99+
Attribute VPP::getSupportedEntryAttributes() const {
100+
using enum Attribute;
101+
return LENGTH;
102+
}

0 commit comments

Comments
 (0)