diff --git a/.gitmodules b/.gitmodules index 338869a93..3a0a7831e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "PakLib"] - path = PakLib - url = https://github.com/RetroView/PakLib.git [submodule "NODLib"] path = NODLib url = https://github.com/RetroView/NODLib.git diff --git a/DataSpec/DNACommon/DNACommon.hpp b/DataSpec/DNACommon/DNACommon.hpp index ce8ff51de..bed3555fd 100644 --- a/DataSpec/DNACommon/DNACommon.hpp +++ b/DataSpec/DNACommon/DNACommon.hpp @@ -2,8 +2,7 @@ #define __DNA_COMMON_HPP__ #include -#include -#include +#include "HECL/HECL.hpp" namespace Retro { @@ -11,50 +10,120 @@ namespace Retro /* This comes up a great deal */ typedef Athena::io::DNA BigDNA; -/* FourCC DNA */ -class DNAFourCC : public BigDNA, public CFourCC +/* PAK 32-bit Unique ID */ +class UniqueID32 : public BigDNA { + uint32_t m_id; public: Delete expl; - void read(Athena::io::IStreamReader& reader) - {_read(reader);} - void write(Athena::io::IStreamWriter& writer) const - {_write(writer);} + inline void read(Athena::io::IStreamReader& reader) + {reader.readUint32();} + inline void write(Athena::io::IStreamWriter& writer) const + {writer.writeUint32(m_id);} + + inline bool operator!=(const UniqueID32& other) const {return m_id != other.m_id;} + inline bool operator==(const UniqueID32& other) const {return m_id == other.m_id;} + inline std::string toString() const + { + char buf[9]; + snprintf(buf, 9, "%08X", m_id); + return std::string(buf); + } }; -/* PAK 32-bit Unique ID DNA */ -class DNAUniqueID32 : public BigDNA, public CUniqueID +/* PAK 64-bit Unique ID */ +class UniqueID64 : public BigDNA { + uint64_t m_id; public: Delete expl; - void read(Athena::io::IStreamReader& reader) - {_read(reader, E_32Bits);} - void write(Athena::io::IStreamWriter& writer) const - {_write(writer);} + inline void read(Athena::io::IStreamReader& reader) + {reader.readUint64();} + inline void write(Athena::io::IStreamWriter& writer) const + {writer.writeUint64(m_id);} + + inline bool operator!=(const UniqueID64& other) const {return m_id != other.m_id;} + inline bool operator==(const UniqueID64& other) const {return m_id == other.m_id;} + inline std::string toString() const + { + char buf[17]; + snprintf(buf, 17, "%16X", m_id); + return std::string(buf); + } }; -/* PAK 64-bit Unique ID DNA */ -class DNAUniqueID64 : public BigDNA, public CUniqueID +/* PAK 128-bit Unique ID */ +class UniqueID128 : public BigDNA { + union + { + uint64_t m_id[2]; +#if __SSE__ + __m128i m_id128; +#endif + }; public: Delete expl; - void read(Athena::io::IStreamReader& reader) - {_read(reader, E_64Bits);} - void write(Athena::io::IStreamWriter& writer) const - {_write(writer);} -}; + inline void read(Athena::io::IStreamReader& reader) + { + m_id[0] = reader.readUint64(); + m_id[1] = reader.readUint64(); + } + inline void write(Athena::io::IStreamWriter& writer) const + { + writer.writeUint64(m_id[0]); + writer.writeUint64(m_id[1]); + } -/* PAK 128-bit Unique ID DNA */ -class DNAUniqueID128 : public BigDNA, public CUniqueID -{ -public: - Delete expl; - void read(Athena::io::IStreamReader& reader) - {_read(reader, E_128Bits);} - void write(Athena::io::IStreamWriter& writer) const - {_write(writer);} + inline bool operator!=(const UniqueID128& other) const + { +#if __SSE__ + return m_id128 != other.m_id128; +#else + return (m_id[0] != other.m_id[0]) || (m_id[1] != other.m_id[1]); +#endif + } + inline bool operator==(const UniqueID128& other) const + { +#if __SSE__ + return m_id128 == other.m_id128; +#else + return (m_id[0] == other.m_id[0]) && (m_id[1] == other.m_id[1]); +#endif + } + inline std::string toString() const + { + char buf[33]; + snprintf(buf, 33, "%16X%16X", m_id[0], m_id[1]); + return std::string(buf); + } }; } +/* Hash template-specializations for UniqueID types */ +namespace std +{ +template<> +struct hash +{ + inline size_t operator()(const Retro::UniqueID32& id) const + {return id.m_id;} +}; + +template<> +struct hash +{ + inline size_t operator()(const Retro::UniqueID64& id) const + {return id.m_id;} +}; + +template<> +struct hash +{ + inline size_t operator()(const Retro::UniqueID128& id) const + {return id.m_id[0] ^ id.m_id[1];} +}; +} + #endif // __DNA_COMMON_HPP__ diff --git a/DataSpec/DNAMP1/DNAMP1.pri b/DataSpec/DNAMP1/DNAMP1.pri index dcba9810b..97d6a888d 100644 --- a/DataSpec/DNAMP1/DNAMP1.pri +++ b/DataSpec/DNAMP1/DNAMP1.pri @@ -1,2 +1,3 @@ HEADERS += \ + $$PWD/PAK.hpp \ $$PWD/MLVL.hpp diff --git a/DataSpec/DNAMP1/PAK.hpp b/DataSpec/DNAMP1/PAK.hpp new file mode 100644 index 000000000..8e4862f0a --- /dev/null +++ b/DataSpec/DNAMP1/PAK.hpp @@ -0,0 +1,115 @@ +#ifndef __DNAMP1_PAK_HPP__ +#define __DNAMP1_PAK_HPP__ + +#include + +#include "../Logging.hpp" +#include "../DNACommon/DNACommon.hpp" + +namespace Retro +{ +namespace DNAMP1 +{ + +class PAK : public BigDNA +{ +public: + struct NameEntry : public BigDNA + { + HECL::FourCC type; + UniqueID32 id; + Value nameLen; + String name; + }; + + struct Entry : public BigDNA + { + Value compressed; + HECL::FourCC type; + UniqueID32 id; + Value size; + Value offset; + }; + +private: + std::vector m_nameEntries; + std::vector m_entries; + std::unordered_map m_idMap; + std::unordered_map m_nameMap; + Delete expl; + +public: + void read(Athena::io::IStreamReader& reader) + { + reader.setEndian(Athena::BigEndian); + atUint32 version = reader.readUint32(); + if (version != 0x00030005) + LogModule.report(LogVisor::FatalError, "unexpected PAK magic"); + reader.readUint32(); + + atUint32 nameCount = reader.readUint32(); + m_nameEntries.clear(); + m_nameEntries.reserve(nameCount); + for (atUint32 n=0 ; n + +#include "../Logging.hpp" +#include "../DNACommon/DNACommon.hpp" + +namespace Retro +{ +namespace DNAMP3 +{ + +class PAK : public BigDNA +{ +public: + struct Header : public BigDNA + { + Value version; + Value headSz; + Value md5sum[16]; + Seek<40, Athena::Current> seek; + } m_header; + + struct NameEntry : public BigDNA + { + String<-1> name; + HECL::FourCC type; + UniqueID64 id; + }; + + struct Entry : public BigDNA + { + atUint32 compressed; + HECL::FourCC type; + UniqueID64 id; + atUint32 size; + atUint32 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 + +namespace Retro +{ +extern LogVisor::LogModule LogModule; +} + +#endif // __RETRO_DATASPEC_LOGGING__ diff --git a/DataSpec/SpecBase.cpp b/DataSpec/SpecBase.cpp index 50cae5c35..c91fefd36 100644 --- a/DataSpec/SpecBase.cpp +++ b/DataSpec/SpecBase.cpp @@ -3,13 +3,15 @@ namespace Retro { -bool SpecBase::canExtract(const ExtractPassInfo& info, HECL::SystemString& reasonNo) +LogVisor::LogModule LogModule("RetroDataSpec"); + +bool SpecBase::canExtract(const ExtractPassInfo& info) { bool isWii; std::unique_ptr disc = NOD::OpenDiscFromImage(info.srcpath.c_str(), isWii); if (!disc) { - reasonNo = _S("Not a valid Nintendo disc image"); + LogModule.report(LogVisor::Error, _S("'%s' not a valid Nintendo disc image"), info.srcpath.c_str()); return false; } const char* gameID = disc->getHeader().gameID; @@ -29,9 +31,7 @@ bool SpecBase::canExtract(const ExtractPassInfo& info, HECL::SystemString& reaso return true; } - HECL::SystemStringView gameIDView(std::string(gameID, 6)); - HECL::SystemStringView gameNameView(disc->getHeader().gameTitle); - reasonNo = gameIDView.sys_str() + _S(" (") + gameNameView.sys_str() + _S(") is not supported"); + LogModule.report(LogVisor::Error, "%.6s (%s) is not supported", gameID, disc->getHeader().gameTitle); return false; } @@ -39,8 +39,7 @@ void SpecBase::doExtract(const HECL::Database::Project& project, const ExtractPa { } -bool SpecBase::canCook(const HECL::Database::Project& project, const CookTaskInfo& info, - HECL::SystemString& reasonNo) +bool SpecBase::canCook(const HECL::Database::Project& project, const CookTaskInfo& info) { } @@ -48,8 +47,7 @@ void SpecBase::doCook(const HECL::Database::Project& project, const CookTaskInfo { } -bool SpecBase::canPackage(const HECL::Database::Project& project, const PackagePassInfo& info, - HECL::SystemString& reasonNo) +bool SpecBase::canPackage(const HECL::Database::Project& project, const PackagePassInfo& info) { } diff --git a/DataSpec/SpecBase.hpp b/DataSpec/SpecBase.hpp index b628d1b2a..954b75f72 100644 --- a/DataSpec/SpecBase.hpp +++ b/DataSpec/SpecBase.hpp @@ -9,17 +9,17 @@ namespace Retro { +extern LogVisor::LogModule LogModule; + struct SpecBase : public HECL::Database::IDataSpec { - bool canExtract(const ExtractPassInfo& info, HECL::SystemString& reasonNo); + bool canExtract(const ExtractPassInfo& info); void doExtract(const HECL::Database::Project& project, const ExtractPassInfo& info); - bool canCook(const HECL::Database::Project& project, const CookTaskInfo& info, - HECL::SystemString& reasonNo); + bool canCook(const HECL::Database::Project& project, const CookTaskInfo& info); void doCook(const HECL::Database::Project& project, const CookTaskInfo& info); - bool canPackage(const HECL::Database::Project& project, const PackagePassInfo& info, - HECL::SystemString& reasonNo); + bool canPackage(const HECL::Database::Project& project, const PackagePassInfo& info); void gatherDependencies(const HECL::Database::Project& project, const PackagePassInfo& info, std::unordered_set& implicitsOut); void doPackage(const HECL::Database::Project& project, const PackagePassInfo& info); diff --git a/DataSpec/SpecMP1.cpp b/DataSpec/SpecMP1.cpp index 7e70996c3..afd4b1002 100644 --- a/DataSpec/SpecMP1.cpp +++ b/DataSpec/SpecMP1.cpp @@ -49,12 +49,12 @@ struct SpecMP1 : public SpecBase } }; -static HECL::Database::DataSpecEntry SpecMP1 -( +HECL::Database::DataSpecEntry SpecMP1 = +{ _S("MP1"), _S("Data specification for original Metroid Prime engine"), [](HECL::Database::DataSpecTool) -> HECL::Database::IDataSpec* {return new struct SpecMP1;} -); +}; } diff --git a/NODLib b/NODLib index f093f633b..c2227fe82 160000 --- a/NODLib +++ b/NODLib @@ -1 +1 @@ -Subproject commit f093f633b44270c6b52834d310407f9faeb18b76 +Subproject commit c2227fe826ef8009dba0d7ff3a2c6e5b19b56a2b diff --git a/PakLib b/PakLib deleted file mode 160000 index 6a71c1fdc..000000000 --- a/PakLib +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6a71c1fdc4b176f1b14d83b87b57a519f8ba534a