14 FileStream stream{path, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
24 if (!std::filesystem::exists(path)) {
29 auto* sdat =
new SDAT{path};
30 auto packFile = std::unique_ptr<PackFile>(sdat);
32 FileStream reader{sdat->fullFilePath};
39 reader.set_big_endian(
true);
42 reader.skip_in<uint32_t>();
44 const auto entryCount = reader.read<uint32_t>();
46 for (uint32_t i = 0; i < entryCount; i++) {
49 entry.
offset = reader.read<uint32_t>();
50 entry.
length = reader.read<uint32_t>();
52 const auto entryPathOffset = reader.read<uint32_t>();
53 const auto oldPos = reader.tell_in();
54 const auto entryPath = sdat->cleanEntryPath(reader.seek_in_u(entryPathOffset +
sizeof(uint32_t) * 2).read_string());
55 reader.seek_in_u(oldPos);
57 sdat->entries.emplace(entryPath, entry);
60 callback(entryPath, entry);
67std::optional<std::vector<std::byte>>
SDAT::readEntry(
const std::string& path_)
const {
82 stream.seek_in_u(entry->offset);
83 return stream.read_bytes(entry->length);
87 entry.
length = buffer.size();
96 const std::string outputPath = outputDir +
'/' + this->
getFilename();
99 uint32_t pathBlockSize = 0;
100 std::vector<std::pair<std::string, Entry*>> entriesToBake;
102 pathBlockSize += path.size() + 1;
103 entriesToBake.emplace_back(path, &entry);
107 std::vector<std::byte> fileData;
108 for (
auto& [path, entry] : entriesToBake) {
109 if (
auto binData = this->
readEntry(path)) {
110 entry->
offset = fileData.size();
112 fileData.insert(fileData.end(), binData->begin(), binData->end());
120 FileStream stream{outputPath, FileStream::OPT_TRUNCATE | FileStream::OPT_CREATE_IF_NONEXISTENT};
123 const auto dirSize =
sizeof(uint32_t) * 3 * (entriesToBake.size() + 1) + pathBlockSize;
128 .set_big_endian(
true)
129 .write<uint32_t>(dirSize - 8)
130 .write<uint32_t>(entriesToBake.size())
131 .pad(dirSize -
sizeof(uint32_t))
132 .seek_out(
sizeof(uint32_t) * 3);
135 auto currentPathOffset = dirSize - pathBlockSize;
136 for (
const auto& [path, entry] : entriesToBake) {
138 .write<uint32_t>(entry->
offset + dirSize)
139 .write<uint32_t>(entry->
length)
140 .write<uint32_t>(currentPathOffset -
sizeof(uint32_t) * 2);
142 const auto oldPos = stream.tell_out();
143 stream.seek_out_u(currentPathOffset).write(path);
144 currentPathOffset = stream.tell_out();
145 stream.seek_out_u(oldPos);
148 callback(path, *entry);
153 stream.seek_out_u(dirSize).write(fileData);
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)
bool bake()
If output folder is an empty string, it will overwrite the original.
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)
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open an SDAT 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 SDAT file.
Attribute getSupportedEntryAttributes() const override
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
constexpr auto SDAT_SIGNATURE