#include "AFSArchive.hh" #include #include #include #include #include #include "Text.hh" AFSArchive::AFSArchive(std::shared_ptr data) : data(data) { struct FileHeader { be_uint32_t magic; le_uint32_t num_files; } __packed_ws__(FileHeader, 8); struct FileEntry { le_uint32_t offset; le_uint32_t size; } __packed_ws__(FileEntry, 8); phosg::StringReader r(*this->data); const auto& header = r.get(); if (header.magic != 0x41465300) { // 'AFS\0' throw std::runtime_error("file is not an AFS archive"); } while (this->entries.size() < header.num_files) { const auto& entry = r.get(); this->entries.emplace_back(Entry{.offset = entry.offset, .size = entry.size}); } } std::pair AFSArchive::get(size_t index) const { const auto& entry = this->entries.at(index); if (entry.offset > this->data->size()) { throw std::out_of_range("entry begins beyond end of archive"); } if (entry.offset + entry.size > this->data->size()) { throw std::out_of_range("entry extends beyond end of archive"); } return std::make_pair(this->data->data() + entry.offset, entry.size); } std::string AFSArchive::get_copy(size_t index) const { auto ret = this->get(index); return std::string(reinterpret_cast(ret.first), ret.second); } phosg::StringReader AFSArchive::get_reader(size_t index) const { auto ret = this->get(index); return phosg::StringReader(ret.first, ret.second); } std::string AFSArchive::generate(const std::vector& files, bool big_endian) { return big_endian ? AFSArchive::generate_t(files) : AFSArchive::generate_t(files); } template std::string AFSArchive::generate_t(const std::vector& files) { phosg::StringWriter w; w.put_u32b(0x41465300); // 'AFS\0' w.put>(files.size()); // It seems entries are aligned to 0x800-byte boundaries, and the file's header is always 0x80000 (!) bytes, most of // which is unused uint32_t data_offset = 0x80000; for (const auto& file : files) { w.put>(data_offset); w.put>(file.size()); data_offset = (data_offset + file.size() + 0x7FF) & (~0x7FF); } w.extend_to(0x80000); for (const auto& file : files) { w.write(file); w.extend_to((w.size() + 0x7FF) & (~0x7FF)); } return std::move(w.str()); }