14 FileStream stream{path, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
24 if (!std::filesystem::exists(path)) {
30 const auto stem = std::filesystem::path{path}.stem().string();
36 auto packFile = std::unique_ptr<PackFile>(vpkVTMB);
38 for (
int i = 0; i <= 9; i++) {
42 for (
int j = 0; j <= 99; j++) {
44 if (!std::filesystem::exists(numberedPath)) {
47 vpkVTMB->openNumbered(i * 100 + j, numberedPath, callback);
51 vpkVTMB->currentArchive++;
56 FileStream reader{path};
57 reader.seek_in(
sizeof(uint32_t) * 2 +
sizeof(uint8_t), std::ios::end);
59 auto fileCount = reader.read<uint32_t>();
60 auto dirOffset = reader.read<uint32_t>();
63 auto version = reader.read<uint8_t>();
74 reader.seek_in(dirOffset);
75 for (uint32_t i = 0; i < fileCount; i++) {
79 auto entryPath = this->
cleanEntryPath(reader.read_string(reader.read<uint32_t>()));
81 entry.
offset = reader.read<uint32_t>();
82 entry.
length = reader.read<uint32_t>();
84 this->
entries.emplace(entryPath, entry);
87 callback(entryPath, entry);
107 stream.seek_in_u(entry->offset);
108 return stream.read_bytes(entry->length);
113 entry.
length = buffer.size();
131 if (!std::filesystem::create_directory(tempDir, ec)) {
145 std::unordered_map<uint16_t, std::vector<std::pair<std::string, Entry*>>> entriesToBake;
148 entriesToBake[entry.archiveIndex] = {};
150 entriesToBake[entry.
archiveIndex].emplace_back(path, &entry);
153 for (
auto& [archiveIndex, entriesToBakeInArchive] : entriesToBake) {
158 for (
auto& [path, entry] : entriesToBakeInArchive) {
159 if (
auto binData = this->readEntry(path)) {
160 entry->offset = stream.tell_out();
161 stream.write(*binData);
169 auto dirOffset = stream.tell_out();
170 for (
const auto& [path, entry] : entriesToBakeInArchive) {
171 stream.write<uint32_t>(path.length());
172 stream.write(path,
false);
173 stream.write<uint32_t>(entry->offset);
174 stream.write<uint32_t>(entry->length);
177 callback(path, *entry);
182 stream.write<uint32_t>(entriesToBakeInArchive.size());
183 stream.write<uint32_t>(dirOffset);
184 stream.write<uint8_t>(0);
187 if (entriesToBake.contains(this->currentArchive)) {
188 this->currentArchive++;
192 this->mergeUnbakedEntries();
193 std::filesystem::remove_all(tempDir, ec);
This class represents the metadata that a file has inside a PackFile.
uint64_t offset
Offset, format-specific meaning - 0 if unused, or if the offset genuinely is 0.
uint32_t archiveIndex
Which external archive this entry is in.
uint64_t length
Length in bytes (in formats with compression, this is the uncompressed length)
EntryCallbackBase< void > EntryCallback
std::optional< Entry > findEntry(const std::string &path_, bool includeUnbaked=true) const
Try to find an entry given the file path.
void runForAllEntriesInternal(const std::function< void(const std::string &, Entry &)> &operation, bool includeUnbaked=true)
std::string getBakeOutputDir(const std::string &outputDir) const
std::string getTruncatedFilepath() const
/home/user/pak01_dir.vpk -> /home/user/pak01
void setFullFilePath(const std::string &outputDir)
std::string cleanEntryPath(const std::string &path) const
static Entry createNewEntry()
static std::optional< std::vector< std::byte > > readUnbakedEntry(const Entry &entry)
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open Vampire: The Masquerade - Bloodlines VPK files.
static std::unique_ptr< PackFile > create(const std::string &path)
Create Vampire: The Masquerade - Bloodlines VPK files.
Attribute getSupportedEntryAttributes() const override
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
std::vector< uint32_t > knownArchives
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
bool bake(const std::string &outputDir_, BakeOptions options, const EntryCallback &callback) override
If output folder is an empty string, it will overwrite the original.
void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options) override
std::string getTruncatedFilestem() const override
/home/user/pak01_dir.vpk -> pak01
void openNumbered(uint32_t archiveIndex, const std::string &path, const EntryCallback &callback)
bool isNumber(char c)
If a char is a numerical character (0-9).
std::string padNumber(int64_t number, int width, char pad='0')
std::string generateUUIDv4()
constexpr std::string_view VPK_VTMB_EXTENSION