11 if (!std::filesystem::exists(path)) {
16 auto* xzp =
new XZP{path};
17 auto packFile = std::unique_ptr<PackFile>(xzp);
19 FileStream reader{xzp->fullFilePath};
27 if (reader.read<uint32_t>() != 6) {
32 const auto preloadDirectoryEntryCount = reader.read<uint32_t>();
33 const auto directoryEntryCount = reader.read<uint32_t>();
34 reader.skip_in<uint32_t>();
36 if (reader.read<uint32_t>() !=
sizeof(uint32_t) * 9) {
41 if (
const auto filepathEntryCount = reader.read<uint32_t>(); filepathEntryCount != directoryEntryCount) {
46 const auto filepathStringsOffset = reader.read<uint32_t>();
47 reader.skip_in<uint32_t>();
50 std::unordered_map<uint32_t, std::vector<std::pair<uint32_t, uint32_t>>> stagedEntryChunks;
51 for (uint32_t i = 0; i < directoryEntryCount; i++) {
52 const auto filepathCRC = reader.read<uint32_t>();
53 const auto chunkLength = reader.read<uint32_t>();
54 const auto chunkOffset = reader.read<uint32_t>();
56 if (!stagedEntryChunks.contains(filepathCRC)) {
57 stagedEntryChunks[filepathCRC] = {};
58 stagedEntryChunks[filepathCRC].emplace_back(chunkOffset, chunkLength);
59 }
else if (stagedEntryChunks[filepathCRC].back().first + stagedEntryChunks[filepathCRC].back().second == chunkOffset) {
60 stagedEntryChunks[filepathCRC].back().second += chunkLength;
62 stagedEntryChunks[filepathCRC].emplace_back(chunkOffset, chunkLength);
67 std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> stagedEntryPreloads;
68 for (uint32_t i = 0; i < preloadDirectoryEntryCount; i++) {
69 const auto filepathCRC = reader.read<uint32_t>();
70 const auto preloadLength = reader.read<uint32_t>();
71 const auto preloadOffset = reader.read<uint32_t>();
73 stagedEntryPreloads[filepathCRC] = {preloadLength, preloadOffset};
77 reader.skip_in<uint16_t>(directoryEntryCount);
80 reader.seek_in(filepathStringsOffset);
81 std::unordered_map<uint32_t, std::string> stagedEntryFilepaths;
82 for (uint32_t i = 0; i < directoryEntryCount; i++) {
83 const auto filepathCRC = reader.read<uint32_t>();
84 const auto filepathOffset = reader.read<uint32_t>();
85 reader.skip_in<uint32_t>();
87 const auto readerPos = reader.tell_in();
88 reader.seek_in_u(filepathOffset);
89 stagedEntryFilepaths[filepathCRC] = reader.read_string();
90 reader.seek_in_u(readerPos);
94 for (
const auto& [filepathCRC, filepath] : stagedEntryFilepaths) {
97 auto entryPath = xzp->cleanEntryPath(filepath);
101 const auto& chunks = stagedEntryChunks[filepathCRC];
102 stream.write<uint32_t>(chunks.size());
105 for (
const auto& chunk : chunks) {
106 entry.
length += chunk.second;
107 stream << chunk.first << chunk.second;
110 if (stagedEntryPreloads.contains(filepathCRC)) {
111 const auto& preload = stagedEntryPreloads[filepathCRC];
112 stream.write<uint32_t>(
true);
113 stream << preload.first << preload.second;
115 stream.write<uint32_t>(
false);
118 xzp->entries.emplace(entryPath, entry);
121 callback(entryPath, entry);
128std::optional<std::vector<std::byte>>
XZP::readEntry(
const std::string& path_)
const {
134 if (entry->unbaked) {
143 std::vector<std::byte> out;
144 BufferStreamReadOnly entryDataStream{entry->extraData};
145 const auto chunks = entryDataStream.read<uint32_t>();
146 for (uint32_t i = 0; i < chunks; i++) {
147 const auto chunkOffset = entryDataStream.read<uint32_t>();
148 const auto chunkLength = entryDataStream.read<uint32_t>();
149 const auto chunkData = stream.seek_in(chunkOffset).read_bytes(chunkLength);
150 out.insert(out.end(), chunkData.begin(), chunkData.end());
This class represents the metadata that a file has inside a PackFile.
uint64_t length
Length in bytes (in formats with compression, this is the uncompressed length)
std::vector< std::byte > extraData
Format-specific (PCK: MD5 hash, VPK: Preloaded data)
EntryCallbackBase< void > EntryCallback
std::optional< Entry > findEntry(const std::string &path_, bool includeUnbaked=true) const
Try to find an entry given the file path.
std::string cleanEntryPath(const std::string &path) const
static Entry createNewEntry()
static std::optional< std::vector< std::byte > > readUnbakedEntry(const Entry &entry)
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 an XZP file.
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
constexpr auto XZP_HEADER_SIGNATURE