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;
133 vpp->flags &= ~FLAG_COMPRESSED;
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);
237 if (!entry->compressedLength) {
245 auto compressedData = stream.read_bytes(entry->compressedLength);
246 mz_ulong uncompressedLength = entry->length;
247 std::vector<std::byte> uncompressedData(uncompressedLength);
248 mz_uncompress(
reinterpret_cast<unsigned char*
>(uncompressedData.data()), &uncompressedLength,
reinterpret_cast<const unsigned char*
>(compressedData.data()), entry->compressedLength);
249 return uncompressedData;
257 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)
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)
static std::unique_ptr< PackFile > open(const std::string &path, const EntryCallback &callback=nullptr)
Open a VPP file.
Attribute getSupportedEntryAttributes() const override
Returns a list of supported entry attributes Mostly for GUI programs that show entries and their meta...
std::vector< std::byte > uncondensedData
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
constexpr uint16_t paddingForAlignment(uint16_t alignment, uint64_t n)
constexpr uint32_t VPP_ALIGNMENT
constexpr uint32_t VPP_SIGNATURE_BIG
constexpr uint32_t VPP_SIGNATURE_LIL