#include "ggpk_vfs.h" #include struct GgpkVfs { Vfs vfs; std::unique_ptr pack; }; std::shared_ptr open_ggpk(std::filesystem::path ggpk_path) { auto ret = std::make_shared(); ret->pack = poe::format::ggpk::index_ggpk(ggpk_path); if (!ret->pack) { return {}; } ret->vfs.open = [](Vfs* vfs, char const* c_path) -> VfsFile* { auto* gvfs = reinterpret_cast(vfs); ggpk::parsed_directory const* dir = gvfs->pack->root_; std::u16string path = poe::util::lowercase(poe::util::to_u16string(c_path)); std::u16string_view tail(path); while (!tail.empty() && dir) { size_t delim = tail.find(u'/'); if (delim == 0) { continue; } std::u16string_view head = tail.substr(0, delim); bool next_found = false; for (auto& child : dir->entries_) { if (poe::util::lowercase(child->name_) == head) { if (delim == std::string_view::npos) { return (VfsFile*)dynamic_cast(child.get()); } else { dir = dynamic_cast(child.get()); tail = tail.substr(delim + 1); next_found = true; } } } if (!next_found) { return nullptr; } } return nullptr; }; ret->vfs.close = [](Vfs* vfs, VfsFile* file) {}; ret->vfs.size = [](Vfs*, VfsFile* file) -> int64_t { auto* f = reinterpret_cast(file); return f ? f->data_size_ : -1; }; ret->vfs.read = [](Vfs* vfs, VfsFile* file, uint8_t* out, int64_t offset, int64_t size) -> int64_t { auto* gvfs = reinterpret_cast(vfs); auto* f = reinterpret_cast(file); if (offset + size > (int64_t)f->data_size_) { return -1; } memcpy(out, gvfs->pack->mapping_.data() + f->data_offset_ + offset, size); return size; }; ret->pack = poe::format::ggpk::index_ggpk(ggpk_path); return ret; } Vfs* borrow_vfs(std::shared_ptr& vfs) { return vfs ? &vfs->vfs : nullptr; }