13 if (!std::filesystem::exists(path)) {
18 auto* gma =
new GMA{path};
19 auto packFile = std::unique_ptr<PackFile>(gma);
21 FileStream reader{gma->fullFilePath};
24 reader.read(gma->header.signature);
29 reader.read(gma->header.version);
30 reader.read(gma->header.steamID);
31 reader.read(gma->header.timestamp);
32 reader.read(gma->header.requiredContent);
33 reader.read(gma->header.addonName);
34 reader.read(gma->header.addonDescription);
35 reader.read(gma->header.addonAuthor);
36 reader.read(gma->header.addonVersion);
38 std::vector<std::pair<std::string, Entry>>
entries;
39 while (reader.read<uint32_t>() > 0) {
42 auto entryPath = reader.read_string();
44 entry.
length = reader.read<uint64_t>();
45 reader.read(entry.
crc32);
47 entries.emplace_back(entryPath, entry);
51 std::size_t offset = reader.tell_in();
52 for (
auto& [entryPath, entry] :
entries) {
53 entry.offset = offset;
54 offset += entry.length;
56 gma->entries.emplace(entryPath, entry);
59 callback(entryPath, entry);
76 if (data.size() <= 4) {
80 const auto checksum = *(
reinterpret_cast<uint32_t*
>(data.data() + data.size()) - 1);
88std::optional<std::vector<std::byte>>
GMA::readEntry(
const std::string& path_)
const {
103 stream.seek_in_u(entry->offset);
104 return stream.read_bytes(entry->length);
108 entry.
length = buffer.size();
118 std::string outputPath = outputDir +
'/' + this->
getFilename();
121 std::vector<std::pair<std::string, Entry*>> entriesToBake;
123 entriesToBake.emplace_back(path, &entry);
127 std::vector<std::byte> fileData;
128 for (
auto& [path, entry] : entriesToBake) {
129 if (
auto binData = this->
readEntry(path)) {
130 fileData.insert(fileData.end(), binData->begin(), binData->end());
137 FileStream stream{outputPath, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
152 for (uint32_t i = 1; i <= entriesToBake.size(); i++) {
154 const auto& [path, entry] = entriesToBake[i - 1];
156 stream.write(entry->
length);
160 callback(path, *entry);
163 stream.write<uint32_t>(0);
166 std::size_t offset = stream.tell_out();
167 for (
auto& [path, entry] : entriesToBake) {
173 stream.write(fileData);
179 auto fileSize = std::filesystem::file_size(outputPath);
180 FileStream stream{outputPath};
185 FileStream stream{outputPath, FileStream::OPT_APPEND};
200GMA::operator std::string()
const {
201 return PackFile::operator std::string() +
202 " | Version v" + std::to_string(this->header.version) +
203 " | Addon Name: \"" + this->header.addonName +
"\"";
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 crc32
CRC32 checksum - 0 if unused.
uint64_t length
Length in bytes (in formats with compression, this is the uncompressed length)
void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options) override
bool verifyPackFileChecksum() const override
Verify the checksum of the entire file, returns true on success Will return true if there is no check...
bool bake(const std::string &outputDir_, BakeOptions options, const EntryCallback &callback) override
If output folder is an empty string, it will overwrite the original.
Attribute getSupportedEntryAttributes() const override
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open a GMA file.
std::vector< std::string > verifyEntryChecksums() const override
Verify the checksums of each file, if a file fails the check its path will be added to the vector If ...
bool hasPackFileChecksum() const override
Returns true if the entire file has a checksum.
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
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.
std::vector< std::string > verifyEntryChecksumsUsingCRC32() const
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)
uint32_t computeCRC32(std::span< const std::byte > buffer)
std::vector< std::byte > readFileBuffer(const std::string &filepath, std::size_t startOffset=0)
constexpr auto GMA_SIGNATURE
bool gma_writeCRCs
GMA - Write CRCs for files and the overall GMA file when baking.