12 FileStream stream{path, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
32 if (!std::filesystem::exists(path)) {
37 auto* pak =
new PAK{path};
38 auto packFile = std::unique_ptr<PackFile>(pak);
40 FileStream reader{pak->fullFilePath};
43 if (
const auto signature = reader.read<uint32_t>(); signature ==
PAK_SIGNATURE) {
54 const auto directoryOffset = reader.read<uint32_t>();
56 const auto fileCount = reader.read<uint32_t>() / (pak->type !=
Type::PAK ? 128 : 64);
58 reader.seek_in(directoryOffset);
59 for (uint32_t i = 0; i < fileCount; i++) {
62 auto entryPath = pak->cleanEntryPath(reader.read_string(pak->getFilenameLength()));
64 entry.
offset = reader.read<uint32_t>();
65 entry.
length = reader.read<uint32_t>();
67 pak->entries.emplace(entryPath, entry);
70 callback(entryPath, entry);
77std::optional<std::vector<std::byte>>
PAK::readEntry(
const std::string& path_)
const {
92 stream.seek_in_u(entry->offset);
93 return stream.read_bytes(entry->length);
97 entry.
length = buffer.size();
106 const std::string outputPath = outputDir +
'/' + this->
getFilename();
109 std::vector<std::pair<std::string, Entry*>> entriesToBake;
111 entriesToBake.emplace_back(path, &entry);
115 std::vector<std::byte> fileData;
116 for (
auto& [path, entry] : entriesToBake) {
117 if (
auto binData = this->
readEntry(path)) {
118 entry->
offset = fileData.size();
120 fileData.insert(fileData.end(), binData->begin(), binData->end());
128 FileStream stream{outputPath, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
135 static constexpr uint32_t DIRECTORY_INDEX =
sizeof(
PAK_SIGNATURE) +
sizeof(uint32_t) * 2;
136 stream.write(DIRECTORY_INDEX);
138 stream.write(directorySize);
141 for (
const auto& [path, entry] : entriesToBake) {
143 stream.write(
static_cast<uint32_t
>(entry->
offset + DIRECTORY_INDEX + directorySize));
144 stream.write(
static_cast<uint32_t
>(entry->
length));
147 callback(path, *entry);
152 stream.write(fileData);
175 switch (this->
type) {
187 switch (this->
type) {
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.
uint64_t length
Length in bytes (in formats with compression, this is the uncompressed length)
static std::unique_ptr< PackFile > create(const std::string &path, Type type=Type::PAK)
Create a PAK file.
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open a PAK file.
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
Attribute getSupportedEntryAttributes() const override
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
uint8_t getFilenameLength() const
uint32_t getSignature() const
void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options) override
bool bake(const std::string &outputDir_, BakeOptions options, const EntryCallback &callback) override
If output folder is an empty string, it will overwrite the original.
EntryCallbackBase< void > EntryCallback
void mergeUnbakedEntries()
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 getFilename() const
/home/user/pak01_dir.vpk -> pak01_dir.vpk
std::string getBakeOutputDir(const std::string &outputDir) const
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)
constexpr auto PAK_HROT_SIGNATURE
constexpr auto PAK_SIN_SIGNATURE
constexpr auto PAK_SIGNATURE
constexpr uint8_t PAK_SIN_FILENAME_MAX_SIZE
constexpr uint8_t PAK_HROT_FILENAME_MAX_SIZE
constexpr uint8_t PAK_FILENAME_MAX_SIZE