#include "PAK.hpp" #include "DNAMP3.hpp" namespace DataSpec::DNAMP3 { const hecl::FourCC CMPD("CMPD"); void PAK::read(athena::io::IStreamReader& reader) { m_header.read(reader); if (m_header.version != 2) Log.report(logvisor::Fatal, "unexpected PAK magic"); reader.seek(8, athena::Current); atUint32 strgSz = reader.readUint32Big(); reader.seek(4, athena::Current); atUint32 rshdSz = reader.readUint32Big(); reader.seek(44, athena::Current); atUint32 dataOffset = 128 + strgSz + rshdSz; atUint64 strgBase = reader.position(); atUint32 nameCount = reader.readUint32Big(); m_nameEntries.clear(); m_nameEntries.reserve(nameCount); for (atUint32 n=0 ; n PAK::Entry::getBuffer(const nod::Node& pak, atUint64& szOut) const { if (compressed) { std::unique_ptr strm = pak.beginReadStream(offset); struct { hecl::FourCC magic; atUint32 blockCount; } head; strm->read(&head, 8); if (head.magic != CMPD) { Log.report(logvisor::Error, "invalid CMPD block"); return std::unique_ptr(); } head.blockCount = hecl::SBig(head.blockCount); struct Block { atUint32 compSz; atUint32 decompSz; }; std::unique_ptr blocks(new Block[head.blockCount]); strm->read(blocks.get(), 8 * head.blockCount); atUint64 maxBlockSz = 0; atUint64 totalDecompSz = 0; for (atUint32 b=0 ; b maxBlockSz) maxBlockSz = block.compSz; totalDecompSz += block.decompSz; } std::unique_ptr compBuf(new atUint8[maxBlockSz]); atUint8* buf = new atUint8[totalDecompSz]; atUint8* bufCur = buf; for (atUint32 b=0 ; bread(compBufCur, block.compSz); if (block.compSz == block.decompSz) { memcpy(bufCur, compBufCur, block.decompSz); bufCur += block.decompSz; } else { atUint32 rem = block.decompSz; while (rem) { atUint16 chunkSz = hecl::SBig(*(atUint16*)compBufCur); compBufCur += 2; lzo_uint dsz = rem; lzo1x_decompress(compBufCur, chunkSz, bufCur, &dsz, nullptr); compBufCur += chunkSz; bufCur += dsz; rem -= dsz; } } } szOut = totalDecompSz; return std::unique_ptr(buf); } else { atUint8* buf = new atUint8[size]; pak.beginReadStream(offset)->read(buf, size); szOut = size; return std::unique_ptr(buf); } } const PAK::Entry* PAK::lookupEntry(const UniqueID64& id) const { auto result = m_entries.find(id); if (result != m_entries.end()) return &result->second; return nullptr; } const PAK::Entry* PAK::lookupEntry(std::string_view name) const { auto result = m_nameMap.find(name.data()); if (result != m_nameMap.end()) { auto result1 = m_entries.find(result->second); if (result1 != m_entries.end()) return &result1->second; } return nullptr; } std::string PAK::bestEntryName(const Entry& entry, bool& named) const { /* Prefer named entries first */ for (const NameEntry& nentry : m_nameEntries) if (nentry.id == entry.id) { named = true; return nentry.name; } /* Otherwise return ID format string */ named = false; return entry.type.toString() + '_' + entry.id.toString(); } }