SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
PackFile.h
Go to the documentation of this file.
1#pragma once
2
3#include <functional>
4#include <memory>
5#include <optional>
6#include <span>
7#include <string>
8#include <string_view>
9#include <unordered_map>
10#include <vector>
11
12#include <sourcepp/Macros.h>
13#include <tsl/htrie_map.h>
14
15#include "Attribute.h"
16#include "Entry.h"
17#include "Options.h"
18
19namespace vpkpp {
20
21// Executable extensions - mostly just for Godot exports
22constexpr std::array<std::string_view, 3> EXECUTABLE_EXTENSIONS{
23 ".exe", // - Windows
24 ".bin", // - Linux + Godot 3 and below (and Generic)
25 ".x86_64", // | Godot 4 (64-bit)
26};
27
28class PackFile {
29public:
30 enum class OpenProperty {
31 DECRYPTION_KEY, // The pack file is encrypted
32 };
33
34 // Accepts the pack file GUID and request property, returns the requested value
35 using OpenPropertyRequest = std::function<std::vector<std::byte>(PackFile* packFile, OpenProperty property)>;
36
38 template<typename R>
39 using EntryCallbackBase = std::function<R(const std::string& path, const Entry& entry)>;
42
43 // Accepts the entry's path
44 using EntryCreation = std::function<EntryOptions(const std::string& path)>;
45
46 using EntryTrie = tsl::htrie_map<char, Entry>;
47
48 PackFile(const PackFile& other) = delete;
49 PackFile& operator=(const PackFile& other) = delete;
50
51 PackFile(PackFile&& other) noexcept = default;
52 PackFile& operator=(PackFile&& other) noexcept = default;
53
54 virtual ~PackFile() = default;
55
57 [[nodiscard]] static std::unique_ptr<PackFile> open(const std::string& path, const EntryCallback& callback = nullptr, const OpenPropertyRequest& requestProperty = nullptr);
58
60 [[nodiscard]] static std::vector<std::string> getOpenableExtensions();
61
63 [[nodiscard]] virtual constexpr bool hasEntryChecksums() const {
64 return false;
65 }
66
69 [[nodiscard]] virtual std::vector<std::string> verifyEntryChecksums() const;
70
72 [[nodiscard]] virtual bool hasPackFileChecksum() const;
73
76 [[nodiscard]] virtual bool verifyPackFileChecksum() const;
77
79 [[nodiscard]] virtual bool hasPackFileSignature() const;
80
83 [[nodiscard]] virtual bool verifyPackFileSignature() const;
84
86 [[nodiscard]] virtual constexpr bool isCaseSensitive() const {
87 return false;
88 }
89
91 [[nodiscard]] bool hasEntry(const std::string& path, bool includeUnbaked = true) const;
92
94 [[nodiscard]] std::optional<Entry> findEntry(const std::string& path_, bool includeUnbaked = true) const;
95
97 [[nodiscard]] virtual std::optional<std::vector<std::byte>> readEntry(const std::string& path_) const = 0;
98
99 [[nodiscard]] std::optional<std::vector<std::byte>> operator[](const std::string& path_) const;
100
102 [[nodiscard]] std::optional<std::string> readEntryText(const std::string& path) const;
103
104 [[nodiscard]] virtual constexpr bool isReadOnly() const noexcept {
105 return false;
106 }
107
109 bool addEntry(const std::string& entryPath, const std::string& filepath, EntryOptions options = {});
110
112 bool addEntry(const std::string& path, std::vector<std::byte>&& buffer, EntryOptions options = {});
113
115 bool addEntry(const std::string& path, std::span<const std::byte> buffer, EntryOptions options = {});
116
118 int64_t addDirectory(const std::string& entryBaseDir, const std::string& dir, EntryOptions options = {});
119
121 int64_t addDirectory(const std::string& entryBaseDir_, const std::string& dir, const EntryCreation& creation);
122
124 virtual bool renameEntry(const std::string& oldPath_, const std::string& newPath_); // NOLINT(*-use-nodiscard)
125
127 virtual bool renameDirectory(const std::string& oldDir_, const std::string& newDir_); // NOLINT(*-use-nodiscard)
128
130 virtual bool removeEntry(const std::string& path_);
131
133 virtual std::size_t removeDirectory(const std::string& dirName_);
134
136 bool bake();
137
139 bool bake(const std::string& outputDir_);
140
142 bool bake(const std::string& outputDir_, BakeOptions options);
143
145 virtual bool bake(const std::string& outputDir_, BakeOptions options, const EntryCallback& callback) = 0;
146
148 bool extractEntry(const std::string& entryPath, const std::string& filepath) const; // NOLINT(*-use-nodiscard)
149
151 bool extractDirectory(const std::string& dir_, const std::string& outputDir) const; // NOLINT(*-use-nodiscard)
152
154 bool extractAll(const std::string& outputDir, bool createUnderPackFileDir = true) const; // NOLINT(*-use-nodiscard)
155
157 bool extractAll(const std::string& outputDir, const EntryPredicate& predicate, bool stripSharedDirs = true) const; // NOLINT(*-use-nodiscard)
158
160 [[nodiscard]] const EntryTrie& getBakedEntries() const;
161
163 [[nodiscard]] const EntryTrie& getUnbakedEntries() const;
164
166 [[nodiscard]] std::size_t getEntryCount(bool includeUnbaked = true) const;
167
169 void runForAllEntries(const EntryCallback& operation, bool includeUnbaked = true) const;
170
172 void runForAllEntries(const std::string& parentDir, const EntryCallback& operation, bool recursive = true, bool includeUnbaked = true) const;
173
175 [[nodiscard]] std::string_view getFilepath() const;
176
178 [[nodiscard]] std::string getTruncatedFilepath() const;
179
181 [[nodiscard]] std::string getFilename() const;
182
184 [[nodiscard]] std::string getTruncatedFilename() const;
185
187 [[nodiscard]] std::string getFilestem() const;
188
190 [[nodiscard]] virtual std::string getTruncatedFilestem() const;
191
194 [[nodiscard]] virtual Attribute getSupportedEntryAttributes() const;
195
196 [[nodiscard]] virtual explicit operator std::string() const;
197
199 [[nodiscard]] static std::string escapeEntryPathForWrite(const std::string& path);
200
201protected:
202 explicit PackFile(std::string fullFilePath_);
203
204 void runForAllEntriesInternal(const std::function<void(const std::string&, Entry&)>& operation, bool includeUnbaked = true);
205
206 void runForAllEntriesInternal(const std::string& parentDir, const std::function<void(const std::string&, Entry&)>& operation, bool recursive = true, bool includeUnbaked = true);
207
208 [[nodiscard]] std::vector<std::string> verifyEntryChecksumsUsingCRC32() const;
209
210 virtual void addEntryInternal(Entry& entry, const std::string& path, std::vector<std::byte>& buffer, EntryOptions options) = 0;
211
212 [[nodiscard]] std::string getBakeOutputDir(const std::string& outputDir) const;
213
214 void mergeUnbakedEntries();
215
216 void setFullFilePath(const std::string& outputDir);
217
218 [[nodiscard]] std::string cleanEntryPath(const std::string& path) const;
219
220 [[nodiscard]] static Entry createNewEntry();
221
222 [[nodiscard]] static std::optional<std::vector<std::byte>> readUnbakedEntry(const Entry& entry);
223
224 using OpenFactoryFunctionBasic = std::function<std::unique_ptr<PackFile>(const std::string& path, const EntryCallback& callback)>;
225 using OpenFactoryFunction = std::function<std::unique_ptr<PackFile>(const std::string& path, const EntryCallback& callback, const OpenPropertyRequest& requestProperty)>;
226
227 static std::unordered_map<std::string, std::vector<OpenFactoryFunction>>& getOpenExtensionRegistry();
228
229 static const OpenFactoryFunction& registerOpenExtensionForTypeFactory(std::string_view extension, const OpenFactoryFunctionBasic& factory);
230
231 static const OpenFactoryFunction& registerOpenExtensionForTypeFactory(std::string_view extension, const OpenFactoryFunction& factory);
232
233 std::string fullFilePath;
236};
237
239public:
240 [[nodiscard]] constexpr bool isReadOnly() const noexcept final {
241 return true;
242 }
243
244 [[nodiscard]] explicit operator std::string() const override;
245
246protected:
247 explicit PackFileReadOnly(const std::string& fullFilePath_);
248
249 void addEntryInternal(Entry& entry, const std::string& path, std::vector<std::byte>& buffer, EntryOptions options) final;
250
251 bool bake(const std::string& outputDir_, BakeOptions options, const EntryCallback& callback) final;
252};
253
254} // namespace vpkpp
255
256#define VPKPP_REGISTER_PACKFILE_OPEN(extension, function) \
257 static inline const OpenFactoryFunction& SOURCEPP_UNIQUE_NAME(packFileOpenTypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(extension, function)
258
259#define VPKPP_REGISTER_PACKFILE_OPEN_EXECUTABLE(function) \
260 static inline const OpenFactoryFunction& SOURCEPP_UNIQUE_NAME(packFileOpenExecutable0TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkpp::EXECUTABLE_EXTENSIONS[0], function); \
261 static inline const OpenFactoryFunction& SOURCEPP_UNIQUE_NAME(packFileOpenExecutable1TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkpp::EXECUTABLE_EXTENSIONS[1], function); \
262 static inline const OpenFactoryFunction& SOURCEPP_UNIQUE_NAME(packFileOpenExecutable2TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkpp::EXECUTABLE_EXTENSIONS[2], function)
This class represents the metadata that a file has inside a PackFile.
Definition Entry.h:14
void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options) final
Definition PackFile.cpp:762
constexpr bool isReadOnly() const noexcept final
Definition PackFile.h:240
PackFileReadOnly(const std::string &fullFilePath_)
Definition PackFile.cpp:755
virtual constexpr bool hasEntryChecksums() const
Returns true if the format has a checksum for each entry.
Definition PackFile.h:63
std::function< std::unique_ptr< PackFile >(const std::string &path, const EntryCallback &callback)> OpenFactoryFunctionBasic
Definition PackFile.h:224
tsl::htrie_map< char, Entry > EntryTrie
Definition PackFile.h:46
std::optional< std::string > readEntryText(const std::string &path) const
Try to read the entry's data to a string.
Definition PackFile.cpp:189
bool extractAll(const std::string &outputDir, bool createUnderPackFileDir=true) const
Extract the contents of the pack file to disk at the given directory.
Definition PackFile.cpp:425
virtual ~PackFile()=default
virtual bool hasPackFileSignature() const
Returns true if the file is signed.
Definition PackFile.cpp:160
EntryCallbackBase< void > EntryCallback
Definition PackFile.h:40
virtual std::size_t removeDirectory(const std::string &dirName_)
Remove a directory.
Definition PackFile.cpp:351
static std::unordered_map< std::string, std::vector< OpenFactoryFunction > > & getOpenExtensionRegistry()
Definition PackFile.cpp:734
static const OpenFactoryFunction & registerOpenExtensionForTypeFactory(std::string_view extension, const OpenFactoryFunctionBasic &factory)
Definition PackFile.cpp:739
virtual bool renameDirectory(const std::string &oldDir_, const std::string &newDir_)
Rename an existing directory.
Definition PackFile.cpp:305
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
virtual bool verifyPackFileChecksum() const
Verify the checksum of the entire file, returns true on success Will return true if there is no check...
Definition PackFile.cpp:156
bool extractDirectory(const std::string &dir_, const std::string &outputDir) const
Extract the given directory to disk under the given output directory.
Definition PackFile.cpp:400
virtual bool verifyPackFileSignature() const
Verify the file signature, returns true on success Will return true if there is no signature ability ...
Definition PackFile.cpp:164
virtual void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options)=0
virtual bool bake(const std::string &outputDir_, BakeOptions options, const EntryCallback &callback)=0
If output folder is an empty string, it will overwrite the original.
bool extractEntry(const std::string &entryPath, const std::string &filepath) const
Extract the given entry to disk at the given file path.
Definition PackFile.cpp:381
int64_t addDirectory(const std::string &entryBaseDir, const std::string &dir, EntryOptions options={})
Adds new entries using the contents of a given directory.
Definition PackFile.cpp:247
std::string fullFilePath
Definition PackFile.h:233
virtual std::string getTruncatedFilestem() const
/home/user/pak01_dir.vpk -> pak01
Definition PackFile.cpp:634
virtual std::vector< std::string > verifyEntryChecksums() const
Verify the checksums of each file, if a file fails the check its path will be added to the vector If ...
Definition PackFile.cpp:148
EntryTrie entries
Definition PackFile.h:234
PackFile & operator=(const PackFile &other)=delete
virtual bool hasPackFileChecksum() const
Returns true if the entire file has a checksum.
Definition PackFile.cpp:152
std::vector< std::string > verifyEntryChecksumsUsingCRC32() const
Definition PackFile.cpp:656
virtual constexpr bool isReadOnly() const noexcept
Definition PackFile.h:104
EntryCallbackBase< bool > EntryPredicate
Definition PackFile.h:41
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr, const OpenPropertyRequest &requestProperty=nullptr)
Open a generic pack file. The parser is selected based on the file extension.
Definition PackFile.cpp:123
PackFile(PackFile &&other) noexcept=default
bool addEntry(const std::string &entryPath, const std::string &filepath, EntryOptions options={})
Add a new entry from a file path - the first parameter is the path in the PackFile,...
Definition PackFile.cpp:203
virtual constexpr bool isCaseSensitive() const
Does the format support case-sensitive file names?
Definition PackFile.h:86
void runForAllEntriesInternal(const std::function< void(const std::string &, Entry &)> &operation, bool includeUnbaked=true)
Definition PackFile.cpp:571
std::function< std::vector< std::byte >(PackFile *packFile, OpenProperty property)> OpenPropertyRequest
Definition PackFile.h:35
std::string getFilestem() const
/home/user/pak01_dir.vpk -> pak01_dir
Definition PackFile.cpp:630
bool hasEntry(const std::string &path, bool includeUnbaked=true) const
Check if an entry exists given the file path.
Definition PackFile.cpp:168
virtual bool renameEntry(const std::string &oldPath_, const std::string &newPath_)
Rename an existing entry.
Definition PackFile.cpp:285
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
static std::string escapeEntryPathForWrite(const std::string &path)
On Windows, some characters and file names are invalid - this escapes the given entry path.
Definition PackFile.cpp:646
std::string getTruncatedFilepath() const
/home/user/pak01_dir.vpk -> /home/user/pak01
Definition PackFile.cpp:617
void runForAllEntries(const EntryCallback &operation, bool includeUnbaked=true) const
Run a callback for each entry in the pack file.
Definition PackFile.cpp:529
void setFullFilePath(const std::string &outputDir)
Definition PackFile.cpp:701
std::function< std::unique_ptr< PackFile >(const std::string &path, const EntryCallback &callback, const OpenPropertyRequest &requestProperty)> OpenFactoryFunction
Definition PackFile.h:225
std::function< EntryOptions(const std::string &path)> EntryCreation
Definition PackFile.h:44
std::string cleanEntryPath(const std::string &path) const
Definition PackFile.cpp:706
virtual Attribute getSupportedEntryAttributes() const
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
Definition PackFile.cpp:638
std::optional< std::vector< std::byte > > operator[](const std::string &path_) const
Definition PackFile.cpp:185
virtual std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const =0
Try to read the entry's data to a bytebuffer.
PackFile(const PackFile &other)=delete
static std::vector< std::string > getOpenableExtensions()
Returns a sorted list of supported extensions for opening, e.g. {".bsp", ".vpk"}.
Definition PackFile.cpp:137
PackFile & operator=(PackFile &&other) noexcept=default
const EntryTrie & getBakedEntries() const
Get entries saved to disk.
Definition PackFile.cpp:512
static Entry createNewEntry()
Definition PackFile.cpp:715
EntryTrie unbakedEntries
Definition PackFile.h:235
std::string getTruncatedFilename() const
/home/user/pak01_dir.vpk -> pak01.vpk
Definition PackFile.cpp:625
std::size_t getEntryCount(bool includeUnbaked=true) const
Get the number of entries in the pack file.
Definition PackFile.cpp:520
virtual bool removeEntry(const std::string &path_)
Remove an entry.
Definition PackFile.cpp:334
std::string_view getFilepath() const
/home/user/pak01_dir.vpk
Definition PackFile.cpp:613
std::function< R(const std::string &path, const Entry &entry)> EntryCallbackBase
Accepts the entry's path and metadata.
Definition PackFile.h:39
const EntryTrie & getUnbakedEntries() const
Get entries that have been added but not yet baked.
Definition PackFile.cpp:516
static std::optional< std::vector< std::byte > > readUnbakedEntry(const Entry &entry)
Definition PackFile.cpp:719
constexpr std::array< std::string_view, 3 > EXECUTABLE_EXTENSIONS
Definition PackFile.h:22
Attribute
Definition Attribute.h:7