13 if (!std::filesystem::exists(path)) {
18 auto* oo7 =
new OO7{path};
19 auto packFile = std::unique_ptr<PackFile>(oo7);
21 FileStream reader{oo7->fullFilePath};
24 reader >> oo7->majorVersion >> oo7->minorVersion;
25 if (oo7->majorVersion != 1 || (oo7->minorVersion != 1 && oo7->minorVersion != 3)) {
30 std::vector<std::string> v3EntriesFixup;
33 std::function<void(
const std::string&,
bool)> readDir;
34 readDir = [&callback, &oo7, &reader, &v3EntriesFixup, &readDir](
const std::string& parentPath,
bool root) {
35 auto currentPath = parentPath +
'/' + reader.read_string(reader.read<uint32_t>(),
false);
39 auto subDirCount = reader.read<uint32_t>();
40 if (oo7->minorVersion == 3) {
41 reader.skip_in<uint32_t>();
44 auto filenameSize = reader.read<uint32_t>();
51 auto entryPath = oo7->cleanEntryPath(currentPath +
'/' + reader.read_string(filenameSize,
false));
53 bool compressed = reader.read<uint8_t>();
54 entry.
length = reader.read<uint32_t>();
58 reader.skip_in<uint32_t>();
61 if (oo7->minorVersion == 1) {
62 entry.
offset = reader.tell_in();
67 reader.skip_in(entry.
length);
70 v3EntriesFixup.push_back(entryPath);
73 oo7->entries.emplace(entryPath, entry);
76 callback(entryPath, entry);
79 for (uint32_t i = 0; i < subDirCount; i++) {
80 readDir(currentPath,
false);
85 for (
const auto& entryPath : v3EntriesFixup) {
86 auto& entry = oo7->entries.at(entryPath);
87 entry.offset = reader.tell_in();
88 if (!entry.compressedLength) {
89 reader.skip_in(entry.length);
91 reader.skip_in(entry.compressedLength);
98 if (oo7->minorVersion == 3 && reader.read<uint32_t>() == 16) {
99 oo7->hasChecksum =
true;
100 reader >> oo7->checksum;
120 uint32_t minOffset = UINT32_MAX;
122 minOffset = (entry.
offset < minOffset) ? entry.
offset : minOffset;
125 data.resize(minOffset - (
sizeof(uint32_t) * 2));
129std::optional<std::vector<std::byte>>
OO7::readEntry(
const std::string& path_)
const {
135 if (entry->unbaked) {
144 stream.seek_in_u(entry->offset);
145 if (!entry->compressedLength) {
146 return stream.read_bytes(entry->length);
150 auto compressedData = stream.read_bytes(entry->compressedLength);
151 mz_ulong uncompressedLength = entry->length;
152 std::vector<std::byte> uncompressedData(uncompressedLength);
153 if (mz_uncompress(
reinterpret_cast<unsigned char*
>(uncompressedData.data()), &uncompressedLength,
reinterpret_cast<const unsigned char*
>(compressedData.data()), entry->compressedLength) != MZ_OK) {
156 return uncompressedData;
164OO7::operator std::string()
const {
165 return PackFileReadOnly::operator std::string() +
166 " | Version v" + std::to_string(this->majorVersion) +
'.' + std::to_string(this->minorVersion);
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)
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 a 007 file.
bool verifyPackFileChecksum() const override
Verify the checksum of the entire file, returns true on success Will return true if there is no check...
std::optional< std::vector< std::byte > > readEntry(const std::string &path_) const override
Try to read the entry's data to a bytebuffer.
bool hasPackFileChecksum() const override
Returns true if the entire file has a checksum.
std::array< std::byte, 16 > checksum
EntryCallbackBase< void > EntryCallback
std::optional< Entry > findEntry(const std::string &path_, bool includeUnbaked=true) const
Try to find an entry given the file path.
void runForAllEntries(const EntryCallback &operation, bool includeUnbaked=true) const
Run a callback for each entry in the pack file.
std::string cleanEntryPath(const std::string &path) const
static Entry createNewEntry()
static std::optional< std::vector< std::byte > > readUnbakedEntry(const Entry &entry)
std::array< std::byte, 16 > computeMD5(std::span< const std::byte > buffer)
std::vector< std::byte > readFileBuffer(const std::string &filepath, std::size_t startOffset=0)