#ifndef __DNAMP3_PAK_HPP__ #define __DNAMP3_PAK_HPP__ #include #include "../Logging.hpp" #include "../DNACommon/DNACommon.hpp" namespace Retro { namespace DNAMP3 { class PAK : public BigDNA { public: struct Header : BigDNA { DECL_DNA Value version; Value headSz; Value md5sum[16]; Seek<40, Athena::Current> seek; } m_header; struct NameEntry : BigDNA { DECL_DNA String<-1> name; HECL::FourCC type; UniqueID64 id; }; struct Entry : BigDNA { DECL_DNA Value compressed; HECL::FourCC type; UniqueID64 id; Value size; Value offset; }; private: std::vector m_nameEntries; std::vector m_entries; std::unordered_map m_idMap; std::unordered_map m_nameMap; size_t m_dataOffset = 0; Delete expl; public: void read(Athena::io::IStreamReader& reader) { reader.setEndian(Athena::BigEndian); m_header.read(reader); if (m_header.version != 2) LogModule.report(LogVisor::FatalError, "unexpected PAK magic"); reader.seek(8, Athena::Current); atUint32 strgSz = reader.readUint32(); reader.seek(4, Athena::Current); atUint32 rshdSz = reader.readUint32(); reader.seek(44, Athena::Current); m_dataOffset = 128 + strgSz + rshdSz; atUint32 nameCount = reader.readUint32(); m_nameEntries.clear(); m_nameEntries.reserve(nameCount); for (atUint32 n=0 ; n::iterator found = m_idMap.find(entry.id); if (found != m_idMap.end()) m_nameMap[entry.name] = found->second; } } void write(Athena::io::IStreamWriter& writer) const { writer.setEndian(Athena::BigEndian); m_header.write(writer); HECL::FourCC("STRG").write(writer); atUint32 strgSz = 4; for (const NameEntry& entry : m_nameEntries) strgSz += entry.name.size() + 13; atUint32 strgPad = ((strgSz + 63) & ~63) - strgSz; strgSz += strgPad; writer.writeUint32(strgSz); HECL::FourCC("RSHD").write(writer); atUint32 rshdSz = 4 + 24 * m_entries.size(); atUint32 rshdPad = ((rshdSz + 63) & ~63) - rshdSz; rshdSz += rshdPad; writer.writeUint32(rshdSz); HECL::FourCC("DATA").write(writer); atUint32 dataSz = 0; for (const Entry& entry : m_entries) dataSz += (entry.size + 63) & ~63; atUint32 dataPad = ((dataSz + 63) & ~63) - dataSz; dataSz += dataPad; writer.writeUint32(dataSz); writer.seek(36, Athena::Current); writer.writeUint32(m_nameEntries.size()); for (const NameEntry& entry : m_nameEntries) entry.write(writer); writer.seek(strgPad, Athena::Current); writer.writeUint32(m_entries.size()); for (const Entry& entry : m_entries) entry.write(writer); writer.seek(rshdPad, Athena::Current); } inline const Entry* lookupEntry(const UniqueID64& id) const { std::unordered_map::const_iterator result = m_idMap.find(id); if (result != m_idMap.end()) return result->second; return nullptr; } inline const Entry* lookupEntry(const std::string& name) const { std::unordered_map::const_iterator result = m_nameMap.find(name); if (result != m_nameMap.end()) return result->second; return nullptr; } inline size_t getDataOffset() const {return m_dataOffset;} }; } } #endif // __DNAMP3_PAK_HPP__