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::string_view EXECUTABLE_EXTENSION0 = ".exe"; // - Windows
23constexpr std::string_view EXECUTABLE_EXTENSION1 = ".bin"; // - Linux + Godot 3 and below (and Generic)
24constexpr std::string_view EXECUTABLE_EXTENSION2 = ".x86_64"; // | Godot 4 (64-bit)
25
26class PackFile {
27public:
28 enum class OpenProperty {
29 DECRYPTION_KEY, // The pack file is encrypted
30 };
31
32 // Accepts the pack file GUID and request property, returns the requested value
33 using OpenPropertyRequest = std::function<std::vector<std::byte>(PackFile* packFile, OpenProperty property)>;
34
36 template<typename R>
37 using EntryCallbackBase = std::function<R(const std::string& path, const Entry& entry)>;
40
41 // Accepts the entry's path
42 using EntryCreation = std::function<EntryOptions(const std::string& path)>;
43
44 using EntryTrie = tsl::htrie_map<char, Entry>;
45
46 PackFile(const PackFile& other) = delete;
47 PackFile& operator=(const PackFile& other) = delete;
48
49 PackFile(PackFile&& other) noexcept = default;
50 PackFile& operator=(PackFile&& other) noexcept = default;
51
52 virtual ~PackFile() = default;
53
55 [[nodiscard]] static std::unique_ptr<PackFile> open(const std::string& path, const EntryCallback& callback = nullptr, const OpenPropertyRequest& requestProperty = nullptr);
56
58 [[nodiscard]] static std::vector<std::string> getOpenableExtensions();
59
61 [[nodiscard]] virtual constexpr bool hasEntryChecksums() const {
62 return false;
63 }
64
67 [[nodiscard]] virtual std::vector<std::string> verifyEntryChecksums() const;
68
70 [[nodiscard]] virtual bool hasPackFileChecksum() const;
71
74 [[nodiscard]] virtual bool verifyPackFileChecksum() const;
75
77 [[nodiscard]] virtual bool hasPackFileSignature() const;
78
81 [[nodiscard]] virtual bool verifyPackFileSignature() const;
82
84 [[nodiscard]] virtual constexpr bool isCaseSensitive() const {
85 return false;
86 }
87
89 [[nodiscard]] bool hasEntry(const std::string& path, bool includeUnbaked = true) const;
90
92 [[nodiscard]] std::optional<Entry> findEntry(const std::string& path_, bool includeUnbaked = true) const;
93
95 [[nodiscard]] virtual std::optional<std::vector<std::byte>> readEntry(const std::string& path_) const = 0;
96
97 [[nodiscard]] std::optional<std::vector<std::byte>> operator[](const std::string& path_) const;
98
100 [[nodiscard]] std::optional<std::string> readEntryText(const std::string& path) const;
101
102 [[nodiscard]] virtual constexpr bool isReadOnly() const noexcept {
103 return false;
104 }
105
107 void addEntry(const std::string& entryPath, const std::string& filepath, EntryOptions options = {});
108
110 void addEntry(const std::string& path, std::vector<std::byte>&& buffer, EntryOptions options = {});
111
113 void addEntry(const std::string& path, std::span<const std::byte> buffer, EntryOptions options = {});
114
116 void addDirectory(const std::string& entryBaseDir, const std::string& dir, EntryOptions options = {});
117
119 void addDirectory(const std::string& entryBaseDir_, const std::string& dir, const EntryCreation& creation);
120
122 virtual bool renameEntry(const std::string& oldPath_, const std::string& newPath_); // NOLINT(*-use-nodiscard)
123
125 virtual bool renameDirectory(const std::string& oldDir_, const std::string& newDir_); // NOLINT(*-use-nodiscard)
126
128 virtual bool removeEntry(const std::string& path_);
129
131 virtual std::size_t removeDirectory(const std::string& dirName_);
132
134 virtual bool bake(const std::string& outputDir_ /*= ""*/, BakeOptions options /*= {}*/, const EntryCallback& callback /*= nullptr*/) = 0;
135
137 bool extractEntry(const std::string& entryPath, const std::string& filepath) const; // NOLINT(*-use-nodiscard)
138
140 bool extractDirectory(const std::string& dir_, const std::string& outputDir) const; // NOLINT(*-use-nodiscard)
141
143 bool extractAll(const std::string& outputDir, bool createUnderPackFileDir = true) const; // NOLINT(*-use-nodiscard)
144
146 bool extractAll(const std::string& outputDir, const EntryPredicate& predicate, bool stripSharedDirs = true) const; // NOLINT(*-use-nodiscard)
147
149 [[nodiscard]] const EntryTrie& getBakedEntries() const;
150
152 [[nodiscard]] const EntryTrie& getUnbakedEntries() const;
153
155 [[nodiscard]] std::size_t getEntryCount(bool includeUnbaked = true) const;
156
158 void runForAllEntries(const EntryCallback& operation, bool includeUnbaked = true) const;
159
161 void runForAllEntries(const std::string& parentDir, const EntryCallback& operation, bool recursive = true, bool includeUnbaked = true) const;
162
164 [[nodiscard]] std::string_view getFilepath() const;
165
167 [[nodiscard]] std::string getTruncatedFilepath() const;
168
170 [[nodiscard]] std::string getFilename() const;
171
173 [[nodiscard]] std::string getTruncatedFilename() const;
174
176 [[nodiscard]] std::string getFilestem() const;
177
179 [[nodiscard]] virtual std::string getTruncatedFilestem() const;
180
183 [[nodiscard]] virtual Attribute getSupportedEntryAttributes() const;
184
185 [[nodiscard]] virtual explicit operator std::string() const;
186
188 [[nodiscard]] static std::string escapeEntryPathForWrite(const std::string& path);
189
190protected:
191 explicit PackFile(std::string fullFilePath_);
192
193 void runForAllEntriesInternal(const std::function<void(const std::string&, Entry&)>& operation, bool includeUnbaked = true);
194
195 void runForAllEntriesInternal(const std::string& parentDir, const std::function<void(const std::string&, Entry&)>& operation, bool recursive = true, bool includeUnbaked = true);
196
197 [[nodiscard]] std::vector<std::string> verifyEntryChecksumsUsingCRC32() const;
198
199 virtual void addEntryInternal(Entry& entry, const std::string& path, std::vector<std::byte>& buffer, EntryOptions options) = 0;
200
201 [[nodiscard]] std::string getBakeOutputDir(const std::string& outputDir) const;
202
203 void mergeUnbakedEntries();
204
205 void setFullFilePath(const std::string& outputDir);
206
207 [[nodiscard]] std::string cleanEntryPath(const std::string& path) const;
208
209 [[nodiscard]] static Entry createNewEntry();
210
211 [[nodiscard]] static std::optional<std::vector<std::byte>> readUnbakedEntry(const Entry& entry);
212
213 using OpenFactoryFunctionBasic = std::function<std::unique_ptr<PackFile>(const std::string& path, const EntryCallback& callback)>;
214 using OpenFactoryFunction = std::function<std::unique_ptr<PackFile>(const std::string& path, const EntryCallback& callback, const OpenPropertyRequest& requestProperty)>;
215
216 static std::unordered_map<std::string, std::vector<OpenFactoryFunction>>& getOpenExtensionRegistry();
217
218 static const OpenFactoryFunction& registerOpenExtensionForTypeFactory(std::string_view extension, const OpenFactoryFunctionBasic& factory);
219
220 static const OpenFactoryFunction& registerOpenExtensionForTypeFactory(std::string_view extension, const OpenFactoryFunction& factory);
221
222 std::string fullFilePath;
225};
226
228public:
229 [[nodiscard]] constexpr bool isReadOnly() const noexcept final {
230 return true;
231 }
232
233 [[nodiscard]] explicit operator std::string() const override;
234
235protected:
236 explicit PackFileReadOnly(const std::string& fullFilePath_);
237
238 void addEntryInternal(Entry& entry, const std::string& path, std::vector<std::byte>& buffer, EntryOptions options) final;
239
240 bool bake(const std::string& outputDir_, BakeOptions options, const EntryCallback& callback) final;
241};
242
243} // namespace vpkpp
244
245#define VPKPP_REGISTER_PACKFILE_OPEN(extension, function) \
246 static inline const OpenFactoryFunction& SOURCEPP_UNIQUE_NAME(packFileOpenTypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(extension, function)
247
248#define VPKPP_REGISTER_PACKFILE_OPEN_EXECUTABLE(function) \
249 static inline const OpenFactoryFunction& SOURCEPP_UNIQUE_NAME(packFileOpenExecutable0TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkpp::EXECUTABLE_EXTENSION0, function); \
250 static inline const OpenFactoryFunction& SOURCEPP_UNIQUE_NAME(packFileOpenExecutable1TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkpp::EXECUTABLE_EXTENSION1, function); \
251 static inline const OpenFactoryFunction& SOURCEPP_UNIQUE_NAME(packFileOpenExecutable2TypeFactoryFunction) = PackFile::registerOpenExtensionForTypeFactory(vpkpp::EXECUTABLE_EXTENSION2, function)
This class represents the metadata that a file has inside a PackFile.
Definition Entry.h:14
bool bake(const std::string &outputDir_, BakeOptions options, const EntryCallback &callback) final
If output folder is an empty string, it will overwrite the original.
Definition PackFile.cpp:739
void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options) final
Definition PackFile.cpp:735
constexpr bool isReadOnly() const noexcept final
Definition PackFile.h:229
PackFileReadOnly(const std::string &fullFilePath_)
Definition PackFile.cpp:728
virtual constexpr bool hasEntryChecksums() const
Returns true if the format has a checksum for each entry.
Definition PackFile.h:61
std::function< std::unique_ptr< PackFile >(const std::string &path, const EntryCallback &callback)> OpenFactoryFunctionBasic
Definition PackFile.h:213
tsl::htrie_map< char, Entry > EntryTrie
Definition PackFile.h:44
std::optional< std::string > readEntryText(const std::string &path) const
Try to read the entry's data to a string.
Definition PackFile.cpp:183
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:398
virtual ~PackFile()=default
virtual bool hasPackFileSignature() const
Returns true if the file is signed.
Definition PackFile.cpp:154
EntryCallbackBase< void > EntryCallback
Definition PackFile.h:38
virtual std::size_t removeDirectory(const std::string &dirName_)
Remove a directory.
Definition PackFile.cpp:336
static std::unordered_map< std::string, std::vector< OpenFactoryFunction > > & getOpenExtensionRegistry()
Definition PackFile.cpp:707
static const OpenFactoryFunction & registerOpenExtensionForTypeFactory(std::string_view extension, const OpenFactoryFunctionBasic &factory)
Definition PackFile.cpp:712
virtual bool renameDirectory(const std::string &oldDir_, const std::string &newDir_)
Rename an existing directory.
Definition PackFile.cpp:290
void mergeUnbakedEntries()
Definition PackFile.cpp:658
std::optional< Entry > findEntry(const std::string &path_, bool includeUnbaked=true) const
Try to find an entry given the file path.
Definition PackFile.cpp:166
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:150
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:373
virtual bool verifyPackFileSignature() const
Verify the file signature, returns true on success Will return true if there is no signature ability ...
Definition PackFile.cpp:158
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:354
std::string fullFilePath
Definition PackFile.h:222
virtual std::string getTruncatedFilestem() const
/home/user/pak01_dir.vpk -> pak01
Definition PackFile.cpp:607
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:142
EntryTrie entries
Definition PackFile.h:223
PackFile & operator=(const PackFile &other)=delete
virtual bool hasPackFileChecksum() const
Returns true if the entire file has a checksum.
Definition PackFile.cpp:146
std::vector< std::string > verifyEntryChecksumsUsingCRC32() const
Definition PackFile.cpp:629
virtual constexpr bool isReadOnly() const noexcept
Definition PackFile.h:102
EntryCallbackBase< bool > EntryPredicate
Definition PackFile.h:39
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:117
PackFile(PackFile &&other) noexcept=default
virtual constexpr bool isCaseSensitive() const
Does the format support case-sensitive file names?
Definition PackFile.h:84
void runForAllEntriesInternal(const std::function< void(const std::string &, Entry &)> &operation, bool includeUnbaked=true)
Definition PackFile.cpp:544
std::function< std::vector< std::byte >(PackFile *packFile, OpenProperty property)> OpenPropertyRequest
Definition PackFile.h:33
std::string getFilestem() const
/home/user/pak01_dir.vpk -> pak01_dir
Definition PackFile.cpp:603
bool hasEntry(const std::string &path, bool includeUnbaked=true) const
Check if an entry exists given the file path.
Definition PackFile.cpp:162
virtual bool renameEntry(const std::string &oldPath_, const std::string &newPath_)
Rename an existing entry.
Definition PackFile.cpp:270
std::string getFilename() const
/home/user/pak01_dir.vpk -> pak01_dir.vpk
Definition PackFile.cpp:594
std::string getBakeOutputDir(const std::string &outputDir) const
Definition PackFile.cpp:643
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:619
std::string getTruncatedFilepath() const
/home/user/pak01_dir.vpk -> /home/user/pak01
Definition PackFile.cpp:590
void runForAllEntries(const EntryCallback &operation, bool includeUnbaked=true) const
Run a callback for each entry in the pack file.
Definition PackFile.cpp:502
void setFullFilePath(const std::string &outputDir)
Definition PackFile.cpp:674
std::function< std::unique_ptr< PackFile >(const std::string &path, const EntryCallback &callback, const OpenPropertyRequest &requestProperty)> OpenFactoryFunction
Definition PackFile.h:214
void addDirectory(const std::string &entryBaseDir, const std::string &dir, EntryOptions options={})
Adds new entries using the contents of a given directory.
Definition PackFile.cpp:234
std::function< EntryOptions(const std::string &path)> EntryCreation
Definition PackFile.h:42
void 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:197
std::string cleanEntryPath(const std::string &path) const
Definition PackFile.cpp:679
virtual Attribute getSupportedEntryAttributes() const
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
Definition PackFile.cpp:611
std::optional< std::vector< std::byte > > operator[](const std::string &path_) const
Definition PackFile.cpp:179
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:131
PackFile & operator=(PackFile &&other) noexcept=default
const EntryTrie & getBakedEntries() const
Get entries saved to disk.
Definition PackFile.cpp:485
static Entry createNewEntry()
Definition PackFile.cpp:688
EntryTrie unbakedEntries
Definition PackFile.h:224
std::string getTruncatedFilename() const
/home/user/pak01_dir.vpk -> pak01.vpk
Definition PackFile.cpp:598
std::size_t getEntryCount(bool includeUnbaked=true) const
Get the number of entries in the pack file.
Definition PackFile.cpp:493
virtual bool removeEntry(const std::string &path_)
Remove an entry.
Definition PackFile.cpp:319
std::string_view getFilepath() const
/home/user/pak01_dir.vpk
Definition PackFile.cpp:586
std::function< R(const std::string &path, const Entry &entry)> EntryCallbackBase
Accepts the entry's path and metadata.
Definition PackFile.h:37
const EntryTrie & getUnbakedEntries() const
Get entries that have been added but not yet baked.
Definition PackFile.cpp:489
static std::optional< std::vector< std::byte > > readUnbakedEntry(const Entry &entry)
Definition PackFile.cpp:692
constexpr std::string_view EXECUTABLE_EXTENSION1
Definition PackFile.h:23
constexpr std::string_view EXECUTABLE_EXTENSION0
Definition PackFile.h:22
Attribute
Definition Attribute.h:7
constexpr std::string_view EXECUTABLE_EXTENSION2
Definition PackFile.h:24