12std::unique_ptr<PackFile>
APK::create(
const std::string& path) {
14 FileStream stream{path, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
17 .write<uint32_t>(
sizeof(uint32_t) * 4)
19 .write<uint32_t>(
sizeof(uint32_t) * 4)
26 if (!std::filesystem::exists(path)) {
31 auto* apk =
new APK{path};
32 auto packFile = std::unique_ptr<PackFile>(apk);
34 FileStream reader{apk->fullFilePath};
39 reader.read<uint32_t>() !=
sizeof(uint32_t) * 4
45 const auto entryCount = reader.read<uint32_t>();
47 auto nextEntryOffset = reader.read<uint32_t>();
48 for (uint32_t i = 0; i < entryCount; i++) {
49 reader.seek_in(nextEntryOffset);
53 auto entryPath = apk->cleanEntryPath(reader.read_string(reader.read<uint32_t>() + 1));
55 entry.
offset = reader.read<uint32_t>();
56 entry.
length = reader.read<uint32_t>();
59 .read(nextEntryOffset)
62 apk->entries.emplace(entryPath, entry);
65 callback(entryPath, entry);
72std::optional<std::vector<std::byte>>
APK::readEntry(
const std::string& path_)
const {
87 stream.seek_in_u(entry->offset);
88 return stream.read_bytes(entry->length);
92 entry.
length = buffer.size();
101 const std::string outputPath = outputDir +
'/' + this->
getFilename();
104 std::vector<std::pair<std::string, Entry*>> entriesToBake;
106 entriesToBake.emplace_back(path, &entry);
110 std::vector<std::byte> fileData;
111 for (
auto& [path, entry] : entriesToBake) {
112 if (
auto binData = this->
readEntry(path)) {
113 entry->
offset = fileData.size();
115 fileData.insert(fileData.end(), binData->begin(), binData->end());
123 FileStream stream{outputPath, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
129 .write<uint32_t>(
sizeof(uint32_t) * 4);
132 static constexpr auto HEADER_OFFSET =
sizeof(uint32_t) * 5;
134 .write<uint32_t>(entriesToBake.size())
135 .write<uint32_t>(HEADER_OFFSET + fileData.size())
139 stream.write(fileData);
142 for (
const auto& [path, entry] : entriesToBake) {
144 .write<uint32_t>(path.size())
146 .write<uint32_t>(entry->
offset + HEADER_OFFSET)
147 .write<uint32_t>(entry->
length)
148 .write<uint32_t>(stream.tell_out() +
sizeof(uint32_t) * 2)
152 callback(path, *entry);
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open an APK file.
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
void addEntryInternal(Entry &entry, const std::string &path, std::vector< std::byte > &buffer, EntryOptions options) override
static std::unique_ptr< PackFile > create(const std::string &path)
Create an APK file.
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...
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)
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 APK_SIGNATURE