13 if (!std::filesystem::exists(path)) {
18 auto* vpp =
new VPP{path};
19 auto packFile = std::unique_ptr<PackFile>(vpp);
21 FileStream reader{vpp->fullFilePath};
25 if (
const auto signature = reader.read<uint32_t>(); signature ==
VPP_SIGNATURE_BIG) {
26 reader.set_big_endian(
true);
32 const auto version = reader.read<uint32_t>();
35 const auto entryCount = reader.read<uint32_t>();
38 if (reader.read<uint32_t>() != std::filesystem::file_size(path)) {
43 static constexpr uint32_t headerSize =
sizeof(uint32_t) * 4;
47 const uint32_t fileTableSize = (60 +
sizeof(uint32_t)) * entryCount;
52 uint32_t entryOffset = 0;
55 for (uint32_t i = 0; i < entryCount; i++) {
59 const auto entryPath = vpp->cleanEntryPath(reader.read_string(60));
62 entry.
length = reader.read<uint32_t>();
65 entry.
offset = entryOffset;
69 vpp->entries.emplace(entryPath, entry);
72 callback(entryPath, entry);
75 }
else if (version == 2) {
77 const auto entryCount = reader.read<uint32_t>();
80 if (reader.read<uint32_t>() != std::filesystem::file_size(path)) {
85 static constexpr uint32_t headerSize =
sizeof(uint32_t) * 4;
89 const uint32_t fileTableSize = (24 +
sizeof(uint32_t) * 2) * entryCount;
94 uint32_t entryOffset = 0;
97 for (uint32_t i = 0; i < entryCount; i++) {
101 const auto entryPath = vpp->cleanEntryPath(reader.read_string(24));
104 entry.
length = reader.read<uint32_t>();
109 if (reader.read<uint32_t>() != entry.
length) {
114 entry.
offset = entryOffset;
118 vpp->entries.emplace(entryPath, entry);
121 callback(entryPath, entry);
124 }
else if (version == 3) {
126 reader.skip_in(64 + 256 +
sizeof(uint32_t));
129 reader >> vpp->flags;
137 reader.skip_in<uint32_t>();
140 const auto entryCount = reader.read<uint32_t>();
143 if (reader.read<uint32_t>() != std::filesystem::file_size(path)) {
148 const auto entryDirectorySize = reader.read<uint32_t>();
149 const auto entryNamesSize = reader.read<uint32_t>();
152 const auto entryDataSizeUncompressed = reader.read<uint32_t>();
153 const auto entryDataSizeCompressed = reader.read<uint32_t>();
164 for (uint32_t i = 0; i < entryCount; i++) {
168 const auto entryNameOffset = reader.read<uint32_t>();
171 reader.skip_in<uint32_t>();
174 entry.
offset = reader.read<uint32_t>();
177 reader.skip_in<uint32_t>();
180 entry.
length = reader.read<uint32_t>();
189 reader.skip_in<uint32_t>();
192 const auto lastPos = reader.tell_in();
194 const auto entryPath = vpp->cleanEntryPath(reader.read_string(entryNamesSize - entryNameOffset));
195 reader.seek_in_u(lastPos);
198 vpp->entries.emplace(entryPath, entry);
201 callback(entryPath, entry);
207 reader.seek_in(vpp->entryBaseOffset);
208 vpp->uncondensedData.resize(entryDataSizeUncompressed);
209 auto compressedData = reader.read_bytes(entryDataSizeCompressed);
210 mz_ulong uncompressedLength = entryDataSizeUncompressed;
211 mz_uncompress(
reinterpret_cast<unsigned char*
>(vpp->uncondensedData.data()), &uncompressedLength,
reinterpret_cast<const unsigned char*
>(compressedData.data()), entryDataSizeCompressed);
220std::optional<std::vector<std::byte>>
VPP::readEntry(
const std::string& path_)
const {
226 if (entry->unbaked) {
233 stream.seek_u(entry->offset);
234 return stream.read_bytes(entry->length);
239 if (!entry->compressedLength) {
247 const auto compressedData = stream.read_bytes(entry->compressedLength);
248 mz_ulong uncompressedLength = entry->length;
249 std::vector<std::byte> uncompressedData(uncompressedLength);
250 mz_uncompress(
reinterpret_cast<unsigned char*
>(uncompressedData.data()), &uncompressedLength,
reinterpret_cast<const unsigned char*
>(compressedData.data()), entry->compressedLength);
251 return uncompressedData;
260 return stream.read_bytes(entry->length);
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 compressedLength
If the format supports compression, this is the compressed length.
uint64_t length
Length in bytes (in formats with compression, this is the uncompressed length)