SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
GRP.cpp
Go to the documentation of this file.
1// ReSharper disable CppRedundantQualifier
2
3#include <vpkpp/format/GRP.h>
4
5#include <filesystem>
6
7#include <FileStream.h>
8
9using namespace sourcepp;
10using namespace vpkpp;
11
12std::unique_ptr<PackFile> GRP::create(const std::string& path) {
13 {
14 FileStream stream{path, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
15 stream
16 .write(GRP_SIGNATURE, false, GRP_SIGNATURE.size())
17 .write<uint32_t>(0);
18 }
19 return GRP::open(path);
20}
21
22std::unique_ptr<PackFile> GRP::open(const std::string& path, const EntryCallback& callback) {
23 if (!std::filesystem::exists(path)) {
24 // File does not exist
25 return nullptr;
26 }
27
28 auto* grp = new GRP{path};
29 auto packFile = std::unique_ptr<PackFile>(grp);
30
31 FileStream reader{grp->fullFilePath};
32 reader.seek_in(0);
33
34 if (reader.read_string(12) != GRP_SIGNATURE) {
35 // File is not a GRP
36 return nullptr;
37 }
38
39 const auto entryCount = reader.read<uint32_t>();
40
41 const auto dirSize = (GRP_FILENAME_MAX_SIZE + sizeof(uint32_t)) * (entryCount + 1);
42 uint32_t currentOffset = dirSize;
43 for (int i = 0; i < entryCount; i++) {
44 Entry entry = createNewEntry();
45
46 auto entryPath = grp->cleanEntryPath(reader.read_string(GRP_FILENAME_MAX_SIZE));
47
48 entry.length = reader.read<uint32_t>();
49
50 entry.offset = currentOffset;
51 currentOffset += entry.length;
52
53 grp->entries.emplace(entryPath, entry);
54
55 if (callback) {
56 callback(entryPath, entry);
57 }
58 }
59
60 return packFile;
61}
62
63std::optional<std::vector<std::byte>> GRP::readEntry(const std::string& path_) const {
64 const auto path = this->cleanEntryPath(path_);
65 const auto entry = this->findEntry(path);
66 if (!entry) {
67 return std::nullopt;
68 }
69 if (entry->unbaked) {
70 return readUnbakedEntry(*entry);
71 }
72
73 // It's baked into the file on disk
74 FileStream stream{this->fullFilePath};
75 if (!stream) {
76 return std::nullopt;
77 }
78 stream.seek_in_u(entry->offset);
79 return stream.read_bytes(entry->length);
80}
81
82void GRP::addEntryInternal(Entry& entry, const std::string&, std::vector<std::byte>& buffer, EntryOptions) {
83 entry.length = buffer.size();
84
85 // Offset will be reset when it's baked
86 entry.offset = 0;
87}
88
89bool GRP::bake(const std::string& outputDir_, BakeOptions, const EntryCallback& callback) {
90 // Get the proper file output folder
91 const std::string outputDir = this->getBakeOutputDir(outputDir_);
92 const std::string outputPath = outputDir + '/' + this->getFilename();
93
94 // Reconstruct data for ease of access
95 std::vector<std::pair<std::string, Entry*>> entriesToBake;
96 this->runForAllEntriesInternal([&entriesToBake](const std::string& path, Entry& entry) {
97 entriesToBake.emplace_back(path, &entry);
98 });
99
100 // Read data before overwriting, we don't know if we're writing to ourself
101 const auto dirSize = (GRP_FILENAME_MAX_SIZE + sizeof(uint32_t)) * (entriesToBake.size() + 1);
102 std::vector<std::byte> fileData;
103 for (auto& [path, entry] : entriesToBake) {
104 if (auto binData = this->readEntry(path)) {
105 entry->offset = fileData.size() + dirSize;
106
107 fileData.insert(fileData.end(), binData->begin(), binData->end());
108 } else {
109 entry->offset = 0;
110 entry->length = 0;
111 }
112 }
113
114 {
115 FileStream stream{outputPath, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
116 stream.seek_out(0);
117
118 // Signature + entry count
119 stream
120 .write(GRP_SIGNATURE, false, GRP_SIGNATURE.size())
121 .write<uint32_t>(entriesToBake.size());
122
123 // Directory
124 for (const auto& [path, entry] : entriesToBake) {
125 stream
126 .write(path, false, GRP_FILENAME_MAX_SIZE)
127 .write<uint32_t>(entry->length);
128
129 if (callback) {
130 callback(path, *entry);
131 }
132 }
133
134 // File data
135 stream.write(fileData);
136 }
137
138 // Clean up
139 this->mergeUnbakedEntries();
140 PackFile::setFullFilePath(outputDir);
141 return true;
142}
143
145 using enum Attribute;
146 return LENGTH;
147}
This class represents the metadata that a file has inside a PackFile.
Definition Entry.h:14
uint64_t offset
Offset, format-specific meaning - 0 if unused, or if the offset genuinely is 0.
Definition Entry.h:33
uint64_t length
Length in bytes (in formats with compression, this is the uncompressed length).
Definition Entry.h:26
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open a GRP file.
Definition GRP.cpp:22
static std::unique_ptr< PackFile > create(const std::string &path)
Create a GRP file.
Definition GRP.cpp:12
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
Definition GRP.cpp:63
Attribute getSupportedEntryAttributes() const override
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
Definition GRP.cpp:144
void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options) override
Definition GRP.cpp:82
EntryCallbackBase< void > EntryCallback
Definition PackFile.h:38
void mergeUnbakedEntries()
Definition PackFile.cpp:685
std::optional< Entry > findEntry(const std::string &path_, bool includeUnbaked=true) const
Try to find an entry given the file path.
Definition PackFile.cpp:172
std::string fullFilePath
Definition PackFile.h:231
void runForAllEntriesInternal(const std::function< void(const std::string &, Entry &)> &operation, bool includeUnbaked=true)
Definition PackFile.cpp:571
bool bake()
If output folder is an empty string, it will overwrite the original.
Definition PackFile.cpp:369
std::string getFilename() const
/home/user/pak01_dir.vpk -> pak01_dir.vpk
Definition PackFile.cpp:621
std::string getBakeOutputDir(const std::string &outputDir) const
Definition PackFile.cpp:670
void setFullFilePath(const std::string &outputDir)
Definition PackFile.cpp:701
std::string cleanEntryPath(const std::string &path) const
Definition PackFile.cpp:706
static Entry createNewEntry()
Definition PackFile.cpp:715
static std::optional< std::vector< std::byte > > readUnbakedEntry(const Entry &entry)
Definition PackFile.cpp:719
constexpr std::string_view GRP_SIGNATURE
Definition GRP.h:10
Attribute
Definition Attribute.h:7
constexpr int8_t GRP_FILENAME_MAX_SIZE
Definition GRP.h:9