mirror of https://github.com/AxioDL/metaforce.git
additional DataSpec imps
This commit is contained in:
parent
fc6b61a63e
commit
043af55580
|
@ -24,6 +24,3 @@ add_library(RetroDataSpec
|
||||||
SpecMP1.cpp
|
SpecMP1.cpp
|
||||||
SpecMP2.cpp
|
SpecMP2.cpp
|
||||||
SpecMP3.cpp)
|
SpecMP3.cpp)
|
||||||
target_link_libraries(RetroDataSpec
|
|
||||||
DNAMP1
|
|
||||||
DNAMP3)
|
|
||||||
|
|
|
@ -107,6 +107,20 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CaseInsensitiveCompare
|
||||||
|
{
|
||||||
|
inline bool operator()(const std::string& lhs, const std::string& rhs) const
|
||||||
|
{
|
||||||
|
std::string lhsl = lhs;
|
||||||
|
std::transform(lhsl.begin(), lhsl.end(), lhsl.begin(), tolower);
|
||||||
|
std::string rhsl = rhs;
|
||||||
|
std::transform(rhsl.begin(), rhsl.end(), rhsl.begin(), tolower);
|
||||||
|
if (lhsl.compare(rhsl) < 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Hash template-specializations for UniqueID types */
|
/* Hash template-specializations for UniqueID types */
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
make_dnalist(liblist
|
make_dnalist(liblist
|
||||||
PAK
|
PAK
|
||||||
MLVL)
|
MLVL
|
||||||
add_library(DNAMP1 ${liblist})
|
STRG)
|
||||||
|
add_library(DNAMP1 ${liblist}
|
||||||
|
PAK.cpp
|
||||||
|
STRG.cpp)
|
||||||
|
|
|
@ -1,65 +1,66 @@
|
||||||
/* Auto generated atdna implementation */
|
|
||||||
#include <Athena/Global.hpp>
|
|
||||||
#include <Athena/IStreamReader.hpp>
|
|
||||||
#include <Athena/IStreamWriter.hpp>
|
|
||||||
|
|
||||||
#include "PAK.hpp"
|
#include "PAK.hpp"
|
||||||
|
|
||||||
void Retro::DNAMP1::PAK::NameEntry::read(Athena::io::IStreamReader& __dna_reader)
|
namespace Retro
|
||||||
{
|
{
|
||||||
/* type */
|
namespace DNAMP1
|
||||||
type.read(__dna_reader);
|
{
|
||||||
/* id */
|
|
||||||
id.read(__dna_reader);
|
void PAK::read(Athena::io::IStreamReader& reader)
|
||||||
__dna_reader.setEndian(Athena::BigEndian);
|
{
|
||||||
/* nameLen */
|
reader.setEndian(Athena::BigEndian);
|
||||||
nameLen = __dna_reader.readUint32();
|
atUint32 version = reader.readUint32();
|
||||||
/* name */
|
if (version != 0x00030005)
|
||||||
name = __dna_reader.readString(nameLen);
|
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<nameCount ; ++n)
|
||||||
|
{
|
||||||
|
m_nameEntries.emplace_back();
|
||||||
|
m_nameEntries.back().read(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
atUint32 count = reader.readUint32();
|
||||||
|
m_entries.clear();
|
||||||
|
m_entries.reserve(count);
|
||||||
|
m_idMap.clear();
|
||||||
|
m_idMap.reserve(count);
|
||||||
|
for (atUint32 e=0 ; e<count ; ++e)
|
||||||
|
{
|
||||||
|
m_entries.emplace_back();
|
||||||
|
m_entries.back().read(reader);
|
||||||
|
m_idMap[m_entries.back().id] = &m_entries.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_nameMap.clear();
|
||||||
|
m_nameMap.reserve(nameCount);
|
||||||
|
for (NameEntry& entry : m_nameEntries)
|
||||||
|
{
|
||||||
|
std::unordered_map<UniqueID32, Entry*>::iterator found = m_idMap.find(entry.id);
|
||||||
|
if (found != m_idMap.end())
|
||||||
|
m_nameMap[entry.name] = found->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Retro::DNAMP1::PAK::NameEntry::write(Athena::io::IStreamWriter& __dna_writer) const
|
void PAK::write(Athena::io::IStreamWriter& writer) const
|
||||||
{
|
{
|
||||||
/* type */
|
writer.setEndian(Athena::BigEndian);
|
||||||
type.write(__dna_writer);
|
writer.writeUint32(0x00030005);
|
||||||
/* id */
|
writer.writeUint32(0);
|
||||||
id.write(__dna_writer);
|
|
||||||
__dna_writer.setEndian(Athena::BigEndian);
|
writer.writeUint32(m_nameEntries.size());
|
||||||
/* nameLen */
|
for (const NameEntry& entry : m_nameEntries)
|
||||||
__dna_writer.writeUint32(nameLen);
|
{
|
||||||
/* name */
|
((NameEntry&)entry).nameLen = entry.name.size();
|
||||||
__dna_writer.writeString(name, nameLen);
|
entry.write(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeUint32(m_entries.size());
|
||||||
|
for (const Entry& entry : m_entries)
|
||||||
|
entry.write(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Retro::DNAMP1::PAK::Entry::read(Athena::io::IStreamReader& __dna_reader)
|
|
||||||
{
|
|
||||||
__dna_reader.setEndian(Athena::BigEndian);
|
|
||||||
/* compressed */
|
|
||||||
compressed = __dna_reader.readUint32();
|
|
||||||
/* type */
|
|
||||||
type.read(__dna_reader);
|
|
||||||
/* id */
|
|
||||||
id.read(__dna_reader);
|
|
||||||
__dna_reader.setEndian(Athena::BigEndian);
|
|
||||||
/* size */
|
|
||||||
size = __dna_reader.readUint32();
|
|
||||||
/* offset */
|
|
||||||
offset = __dna_reader.readUint32();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Retro::DNAMP1::PAK::Entry::write(Athena::io::IStreamWriter& __dna_writer) const
|
|
||||||
{
|
|
||||||
__dna_writer.setEndian(Athena::BigEndian);
|
|
||||||
/* compressed */
|
|
||||||
__dna_writer.writeUint32(compressed);
|
|
||||||
/* type */
|
|
||||||
type.write(__dna_writer);
|
|
||||||
/* id */
|
|
||||||
id.write(__dna_writer);
|
|
||||||
__dna_writer.setEndian(Athena::BigEndian);
|
|
||||||
/* size */
|
|
||||||
__dna_writer.writeUint32(size);
|
|
||||||
/* offset */
|
|
||||||
__dna_writer.writeUint32(offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,64 +38,9 @@ private:
|
||||||
std::vector<Entry> m_entries;
|
std::vector<Entry> m_entries;
|
||||||
std::unordered_map<UniqueID32, Entry*> m_idMap;
|
std::unordered_map<UniqueID32, Entry*> m_idMap;
|
||||||
std::unordered_map<std::string, Entry*> m_nameMap;
|
std::unordered_map<std::string, Entry*> m_nameMap;
|
||||||
Delete expl;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void read(Athena::io::IStreamReader& reader)
|
DECL_EXPLICIT_DNA
|
||||||
{
|
|
||||||
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<nameCount ; ++n)
|
|
||||||
{
|
|
||||||
m_nameEntries.emplace_back();
|
|
||||||
m_nameEntries.back().read(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
atUint32 count = reader.readUint32();
|
|
||||||
m_entries.clear();
|
|
||||||
m_entries.reserve(count);
|
|
||||||
m_idMap.clear();
|
|
||||||
m_idMap.reserve(count);
|
|
||||||
for (atUint32 e=0 ; e<count ; ++e)
|
|
||||||
{
|
|
||||||
m_entries.emplace_back();
|
|
||||||
m_entries.back().read(reader);
|
|
||||||
m_idMap[m_entries.back().id] = &m_entries.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_nameMap.clear();
|
|
||||||
m_nameMap.reserve(nameCount);
|
|
||||||
for (NameEntry& entry : m_nameEntries)
|
|
||||||
{
|
|
||||||
std::unordered_map<UniqueID32, Entry*>::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);
|
|
||||||
writer.writeUint32(0x00030005);
|
|
||||||
writer.writeUint32(0);
|
|
||||||
|
|
||||||
writer.writeUint32(m_nameEntries.size());
|
|
||||||
for (const NameEntry& entry : m_nameEntries)
|
|
||||||
{
|
|
||||||
((NameEntry&)entry).nameLen = entry.name.size();
|
|
||||||
entry.write(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.writeUint32(m_entries.size());
|
|
||||||
for (const Entry& entry : m_entries)
|
|
||||||
entry.write(writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const Entry* lookupEntry(const UniqueID32& id) const
|
inline const Entry* lookupEntry(const UniqueID32& id) const
|
||||||
{
|
{
|
||||||
|
@ -112,6 +57,9 @@ public:
|
||||||
return result->second;
|
return result->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::vector<Entry>::iterator begin() {return m_entries.begin();}
|
||||||
|
inline std::vector<Entry>::iterator end() {return m_entries.end();}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include "STRG.hpp"
|
||||||
|
#include "../Logging.hpp"
|
||||||
|
|
||||||
|
namespace Retro
|
||||||
|
{
|
||||||
|
namespace DNAMP1
|
||||||
|
{
|
||||||
|
|
||||||
|
const HECL::FourCC ENGLfcc("ENGL");
|
||||||
|
const HECL::FourCC FRENfcc("FREN");
|
||||||
|
const HECL::FourCC GERMfcc("GERM");
|
||||||
|
const HECL::FourCC SPANfcc("SPAN");
|
||||||
|
const HECL::FourCC ITALfcc("ITAL");
|
||||||
|
const HECL::FourCC JAPNfcc("JAPN");
|
||||||
|
|
||||||
|
void STRG::read(Athena::io::IStreamReader& reader)
|
||||||
|
{
|
||||||
|
uint32_t magic = reader.readUint32();
|
||||||
|
if (magic != 0x87654321)
|
||||||
|
LogModule.report(LogVisor::FatalError, "invalid STRG magic");
|
||||||
|
|
||||||
|
version = reader.readUint32();
|
||||||
|
langCount = reader.readUint32();
|
||||||
|
strCount = reader.readUint32();
|
||||||
|
|
||||||
|
langs.clear();
|
||||||
|
langs.reserve(langCount);
|
||||||
|
for (uint32_t l=0 ; l<langCount ; ++l)
|
||||||
|
{
|
||||||
|
langs.emplace_back();
|
||||||
|
Language& lang = langs.back();
|
||||||
|
lang.lang.read(reader);
|
||||||
|
reader.readUint32();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t l=0 ; l<langCount ; ++l)
|
||||||
|
{
|
||||||
|
Language& lang = langs[l];
|
||||||
|
reader.readUint32();
|
||||||
|
for (uint32_t s=0 ; s<strCount ; ++s)
|
||||||
|
reader.readUint32();
|
||||||
|
for (uint32_t s=0 ; s<strCount ; ++s)
|
||||||
|
lang.strings.push_back(reader.readWString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void STRG::write(Athena::io::IStreamWriter& writer) const
|
||||||
|
{
|
||||||
|
writer.writeUint32(0x87654321);
|
||||||
|
writer.writeUint32(version);
|
||||||
|
writer.writeUint32(langs.size());
|
||||||
|
writer.writeUint32(strCount);
|
||||||
|
|
||||||
|
uint32_t offset = 0;
|
||||||
|
for (const Language& lang : langs)
|
||||||
|
{
|
||||||
|
lang.lang.write(writer);
|
||||||
|
writer.writeUint32(offset);
|
||||||
|
offset += strCount * 4 + 4;
|
||||||
|
for (uint32_t s=0 ; s<strCount ; ++s)
|
||||||
|
{
|
||||||
|
if (s < lang.strings.size())
|
||||||
|
offset += lang.strings[s].size() * 2 + 1;
|
||||||
|
else
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Language& lang : langs)
|
||||||
|
{
|
||||||
|
offset = strCount * 4;
|
||||||
|
for (uint32_t s=0 ; s<strCount ; ++s)
|
||||||
|
{
|
||||||
|
writer.writeUint32(offset);
|
||||||
|
if (s < lang.strings.size())
|
||||||
|
offset += lang.strings[s].size() * 2 + 1;
|
||||||
|
else
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t s=0 ; s<strCount ; ++s)
|
||||||
|
{
|
||||||
|
if (s < lang.strings.size())
|
||||||
|
writer.writeWString(lang.strings[s]);
|
||||||
|
else
|
||||||
|
writer.writeUByte(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef __DNAMP1_STRG_HPP__
|
||||||
|
#define __DNAMP1_STRG_HPP__
|
||||||
|
|
||||||
|
#include "../DNACommon/DNACommon.hpp"
|
||||||
|
|
||||||
|
namespace Retro
|
||||||
|
{
|
||||||
|
namespace DNAMP1
|
||||||
|
{
|
||||||
|
|
||||||
|
extern const HECL::FourCC ENGLfcc;
|
||||||
|
extern const HECL::FourCC FRENfcc;
|
||||||
|
extern const HECL::FourCC GERMfcc;
|
||||||
|
extern const HECL::FourCC SPANfcc;
|
||||||
|
extern const HECL::FourCC ITALfcc;
|
||||||
|
extern const HECL::FourCC JAPNfcc;
|
||||||
|
|
||||||
|
struct STRG : BigDNA
|
||||||
|
{
|
||||||
|
DECL_EXPLICIT_DNA
|
||||||
|
atUint32 version;
|
||||||
|
atUint32 langCount;
|
||||||
|
atUint32 strCount;
|
||||||
|
|
||||||
|
struct Language
|
||||||
|
{
|
||||||
|
HECL::FourCC lang;
|
||||||
|
std::vector<std::wstring> strings;
|
||||||
|
};
|
||||||
|
std::vector<Language> langs;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __DNAMP1_STRG_HPP__
|
|
@ -1 +1,3 @@
|
||||||
|
make_dnalist(liblist
|
||||||
|
MLVL)
|
||||||
|
add_library(DNAMP2 ${liblist})
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
#include "../DNACommon/DNACommon.hpp"
|
||||||
|
|
||||||
|
namespace Retro
|
||||||
|
{
|
||||||
|
namespace DNAMP2
|
||||||
|
{
|
||||||
|
|
||||||
|
struct MLVL : BigDNA
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
HECL::FourCC magic;
|
||||||
|
Value<atUint32> version;
|
||||||
|
UniqueID32 worldNameId;
|
||||||
|
UniqueID32 darkWorldNameId;
|
||||||
|
Value<atUint32> unk;
|
||||||
|
UniqueID32 saveWorldId;
|
||||||
|
UniqueID32 worldSkyboxId;
|
||||||
|
|
||||||
|
Value<atUint32> areaCount;
|
||||||
|
struct Area : BigDNA
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
UniqueID32 areaNameId;
|
||||||
|
Value<atVec4f> transformMtx[3];
|
||||||
|
Value<atVec3f> aabb[2];
|
||||||
|
UniqueID32 areaMREAId;
|
||||||
|
Value<atUint32> areaId;
|
||||||
|
|
||||||
|
Value<atUint32> attachedAreaCount;
|
||||||
|
Vector<atUint16, DNA_COUNT(attachedAreaCount)> attachedAreas;
|
||||||
|
Value<atUint32> padding;
|
||||||
|
|
||||||
|
Value<atUint32> depCount;
|
||||||
|
struct Dependency : BigDNA
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
UniqueID32 id;
|
||||||
|
HECL::FourCC type;
|
||||||
|
};
|
||||||
|
Vector<Dependency, DNA_COUNT(depCount)> deps;
|
||||||
|
|
||||||
|
Value<atUint32> depLayerCount;
|
||||||
|
Vector<atUint32, DNA_COUNT(depLayerCount)> depLayers;
|
||||||
|
|
||||||
|
Value<atUint32> dockCount;
|
||||||
|
struct Dock : BigDNA
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
Value<atUint32> endpointCount;
|
||||||
|
struct Endpoint : BigDNA
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
Value<atUint32> areaIdx;
|
||||||
|
Value<atUint32> dockIdx;
|
||||||
|
};
|
||||||
|
HECL::FourCC type;
|
||||||
|
Vector<Endpoint, DNA_COUNT(endpointCount)> endpoints;
|
||||||
|
|
||||||
|
Value<atUint32> planeVertCount;
|
||||||
|
Vector<atVec3f, DNA_COUNT(planeVertCount)> planeVerts;
|
||||||
|
};
|
||||||
|
Vector<Dock, DNA_COUNT(dockCount)> docks;
|
||||||
|
|
||||||
|
Value<atUint32> relCount;
|
||||||
|
Vector<String<-1>, DNA_COUNT(relCount)> relFilenames;
|
||||||
|
Value<atUint32> relOffsetCount;
|
||||||
|
Vector<atUint32, DNA_COUNT(relOffsetCount)> relOffsets;
|
||||||
|
|
||||||
|
Value<atUint32> unk1;
|
||||||
|
String<-1> internalAreaName;
|
||||||
|
};
|
||||||
|
|
||||||
|
UniqueID32 worldMap;
|
||||||
|
Value<atUint8> unknown2;
|
||||||
|
Value<atUint32> unknown3;
|
||||||
|
|
||||||
|
Value<atUint32> layerFlagCount;
|
||||||
|
struct LayerFlags : BigDNA
|
||||||
|
{
|
||||||
|
DECL_DNA
|
||||||
|
Value<atUint32> layerCount;
|
||||||
|
Value<atUint64> flags;
|
||||||
|
};
|
||||||
|
Vector<LayerFlags, DNA_COUNT(layerFlagCount)> layerFlags;
|
||||||
|
|
||||||
|
Value<atUint32> layerNameCount;
|
||||||
|
Vector<String<-1>, DNA_COUNT(layerNameCount)> layerNames;
|
||||||
|
|
||||||
|
Value<atUint32> layerNameOffsetCount;
|
||||||
|
Vector<atUint32, DNA_COUNT(layerNameOffsetCount)> layerNameOffsets;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
make_dnalist(liblist
|
make_dnalist(liblist
|
||||||
PAK)
|
PAK)
|
||||||
add_library(DNAMP3 ${liblist})
|
add_library(DNAMP3 ${liblist}
|
||||||
|
PAK.cpp)
|
||||||
|
|
|
@ -1,145 +1,93 @@
|
||||||
/* Auto generated atdna implementation */
|
|
||||||
#include <Athena/Global.hpp>
|
|
||||||
#include <Athena/IStreamReader.hpp>
|
|
||||||
#include <Athena/IStreamWriter.hpp>
|
|
||||||
|
|
||||||
#include "PAK.hpp"
|
#include "PAK.hpp"
|
||||||
|
|
||||||
void Retro::DNAMP3::PAK::Header::read(Athena::io::IStreamReader& __dna_reader)
|
namespace Retro
|
||||||
{
|
{
|
||||||
__dna_reader.setEndian(Athena::BigEndian);
|
namespace DNAMP3
|
||||||
/* version */
|
{
|
||||||
version = __dna_reader.readUint32();
|
|
||||||
/* headSz */
|
void PAK::read(Athena::io::IStreamReader& reader)
|
||||||
headSz = __dna_reader.readUint32();
|
{
|
||||||
/* md5sum[0] */
|
reader.setEndian(Athena::BigEndian);
|
||||||
md5sum[0] = __dna_reader.readUByte();
|
m_header.read(reader);
|
||||||
/* md5sum[1] */
|
if (m_header.version != 2)
|
||||||
md5sum[1] = __dna_reader.readUByte();
|
LogModule.report(LogVisor::FatalError, "unexpected PAK magic");
|
||||||
/* md5sum[2] */
|
|
||||||
md5sum[2] = __dna_reader.readUByte();
|
reader.seek(8, Athena::Current);
|
||||||
/* md5sum[3] */
|
atUint32 strgSz = reader.readUint32();
|
||||||
md5sum[3] = __dna_reader.readUByte();
|
reader.seek(4, Athena::Current);
|
||||||
/* md5sum[4] */
|
atUint32 rshdSz = reader.readUint32();
|
||||||
md5sum[4] = __dna_reader.readUByte();
|
reader.seek(44, Athena::Current);
|
||||||
/* md5sum[5] */
|
m_dataOffset = 128 + strgSz + rshdSz;
|
||||||
md5sum[5] = __dna_reader.readUByte();
|
|
||||||
/* md5sum[6] */
|
atUint32 nameCount = reader.readUint32();
|
||||||
md5sum[6] = __dna_reader.readUByte();
|
m_nameEntries.clear();
|
||||||
/* md5sum[7] */
|
m_nameEntries.reserve(nameCount);
|
||||||
md5sum[7] = __dna_reader.readUByte();
|
for (atUint32 n=0 ; n<nameCount ; ++n)
|
||||||
/* md5sum[8] */
|
{
|
||||||
md5sum[8] = __dna_reader.readUByte();
|
m_nameEntries.emplace_back();
|
||||||
/* md5sum[9] */
|
m_nameEntries.back().read(reader);
|
||||||
md5sum[9] = __dna_reader.readUByte();
|
}
|
||||||
/* md5sum[10] */
|
reader.seek((reader.position() + 63) & ~63, Athena::Begin);
|
||||||
md5sum[10] = __dna_reader.readUByte();
|
|
||||||
/* md5sum[11] */
|
atUint32 count = reader.readUint32();
|
||||||
md5sum[11] = __dna_reader.readUByte();
|
m_entries.clear();
|
||||||
/* md5sum[12] */
|
m_entries.reserve(count);
|
||||||
md5sum[12] = __dna_reader.readUByte();
|
m_idMap.clear();
|
||||||
/* md5sum[13] */
|
m_idMap.reserve(count);
|
||||||
md5sum[13] = __dna_reader.readUByte();
|
for (atUint32 e=0 ; e<count ; ++e)
|
||||||
/* md5sum[14] */
|
{
|
||||||
md5sum[14] = __dna_reader.readUByte();
|
m_entries.emplace_back();
|
||||||
/* md5sum[15] */
|
m_entries.back().read(reader);
|
||||||
md5sum[15] = __dna_reader.readUByte();
|
m_idMap[m_entries.back().id] = &m_entries.back();
|
||||||
/* seek */
|
}
|
||||||
__dna_reader.seek(40, Athena::Current);
|
|
||||||
|
m_nameMap.clear();
|
||||||
|
m_nameMap.reserve(nameCount);
|
||||||
|
for (NameEntry& entry : m_nameEntries)
|
||||||
|
{
|
||||||
|
std::unordered_map<UniqueID64, Entry*>::iterator found = m_idMap.find(entry.id);
|
||||||
|
if (found != m_idMap.end())
|
||||||
|
m_nameMap[entry.name] = found->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void PAK::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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Retro::DNAMP3::PAK::Header::write(Athena::io::IStreamWriter& __dna_writer) const
|
|
||||||
{
|
|
||||||
__dna_writer.setEndian(Athena::BigEndian);
|
|
||||||
/* version */
|
|
||||||
__dna_writer.writeUint32(version);
|
|
||||||
/* headSz */
|
|
||||||
__dna_writer.writeUint32(headSz);
|
|
||||||
/* md5sum[0] */
|
|
||||||
__dna_writer.writeUByte(md5sum[0]);
|
|
||||||
/* md5sum[1] */
|
|
||||||
__dna_writer.writeUByte(md5sum[1]);
|
|
||||||
/* md5sum[2] */
|
|
||||||
__dna_writer.writeUByte(md5sum[2]);
|
|
||||||
/* md5sum[3] */
|
|
||||||
__dna_writer.writeUByte(md5sum[3]);
|
|
||||||
/* md5sum[4] */
|
|
||||||
__dna_writer.writeUByte(md5sum[4]);
|
|
||||||
/* md5sum[5] */
|
|
||||||
__dna_writer.writeUByte(md5sum[5]);
|
|
||||||
/* md5sum[6] */
|
|
||||||
__dna_writer.writeUByte(md5sum[6]);
|
|
||||||
/* md5sum[7] */
|
|
||||||
__dna_writer.writeUByte(md5sum[7]);
|
|
||||||
/* md5sum[8] */
|
|
||||||
__dna_writer.writeUByte(md5sum[8]);
|
|
||||||
/* md5sum[9] */
|
|
||||||
__dna_writer.writeUByte(md5sum[9]);
|
|
||||||
/* md5sum[10] */
|
|
||||||
__dna_writer.writeUByte(md5sum[10]);
|
|
||||||
/* md5sum[11] */
|
|
||||||
__dna_writer.writeUByte(md5sum[11]);
|
|
||||||
/* md5sum[12] */
|
|
||||||
__dna_writer.writeUByte(md5sum[12]);
|
|
||||||
/* md5sum[13] */
|
|
||||||
__dna_writer.writeUByte(md5sum[13]);
|
|
||||||
/* md5sum[14] */
|
|
||||||
__dna_writer.writeUByte(md5sum[14]);
|
|
||||||
/* md5sum[15] */
|
|
||||||
__dna_writer.writeUByte(md5sum[15]);
|
|
||||||
/* seek */
|
|
||||||
__dna_writer.seek(40, Athena::Current);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Retro::DNAMP3::PAK::NameEntry::read(Athena::io::IStreamReader& __dna_reader)
|
|
||||||
{
|
|
||||||
/* name */
|
|
||||||
name = __dna_reader.readString(-1);
|
|
||||||
/* type */
|
|
||||||
type.read(__dna_reader);
|
|
||||||
/* id */
|
|
||||||
id.read(__dna_reader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Retro::DNAMP3::PAK::NameEntry::write(Athena::io::IStreamWriter& __dna_writer) const
|
|
||||||
{
|
|
||||||
/* name */
|
|
||||||
__dna_writer.writeString(name, -1);
|
|
||||||
/* type */
|
|
||||||
type.write(__dna_writer);
|
|
||||||
/* id */
|
|
||||||
id.write(__dna_writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Retro::DNAMP3::PAK::Entry::read(Athena::io::IStreamReader& __dna_reader)
|
|
||||||
{
|
|
||||||
__dna_reader.setEndian(Athena::BigEndian);
|
|
||||||
/* compressed */
|
|
||||||
compressed = __dna_reader.readUint32();
|
|
||||||
/* type */
|
|
||||||
type.read(__dna_reader);
|
|
||||||
/* id */
|
|
||||||
id.read(__dna_reader);
|
|
||||||
__dna_reader.setEndian(Athena::BigEndian);
|
|
||||||
/* size */
|
|
||||||
size = __dna_reader.readUint32();
|
|
||||||
/* offset */
|
|
||||||
offset = __dna_reader.readUint32();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Retro::DNAMP3::PAK::Entry::write(Athena::io::IStreamWriter& __dna_writer) const
|
|
||||||
{
|
|
||||||
__dna_writer.setEndian(Athena::BigEndian);
|
|
||||||
/* compressed */
|
|
||||||
__dna_writer.writeUint32(compressed);
|
|
||||||
/* type */
|
|
||||||
type.write(__dna_writer);
|
|
||||||
/* id */
|
|
||||||
id.write(__dna_writer);
|
|
||||||
__dna_writer.setEndian(Athena::BigEndian);
|
|
||||||
/* size */
|
|
||||||
__dna_writer.writeUint32(size);
|
|
||||||
/* offset */
|
|
||||||
__dna_writer.writeUint32(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -47,92 +47,9 @@ private:
|
||||||
std::unordered_map<UniqueID64, Entry*> m_idMap;
|
std::unordered_map<UniqueID64, Entry*> m_idMap;
|
||||||
std::unordered_map<std::string, Entry*> m_nameMap;
|
std::unordered_map<std::string, Entry*> m_nameMap;
|
||||||
size_t m_dataOffset = 0;
|
size_t m_dataOffset = 0;
|
||||||
Delete expl;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void read(Athena::io::IStreamReader& reader)
|
DECL_EXPLICIT_DNA
|
||||||
{
|
|
||||||
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<nameCount ; ++n)
|
|
||||||
{
|
|
||||||
m_nameEntries.emplace_back();
|
|
||||||
m_nameEntries.back().read(reader);
|
|
||||||
}
|
|
||||||
reader.seek((reader.position() + 63) & ~63, Athena::Begin);
|
|
||||||
|
|
||||||
atUint32 count = reader.readUint32();
|
|
||||||
m_entries.clear();
|
|
||||||
m_entries.reserve(count);
|
|
||||||
m_idMap.clear();
|
|
||||||
m_idMap.reserve(count);
|
|
||||||
for (atUint32 e=0 ; e<count ; ++e)
|
|
||||||
{
|
|
||||||
m_entries.emplace_back();
|
|
||||||
m_entries.back().read(reader);
|
|
||||||
m_idMap[m_entries.back().id] = &m_entries.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_nameMap.clear();
|
|
||||||
m_nameMap.reserve(nameCount);
|
|
||||||
for (NameEntry& entry : m_nameEntries)
|
|
||||||
{
|
|
||||||
std::unordered_map<UniqueID64, Entry*>::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
|
inline const Entry* lookupEntry(const UniqueID64& id) const
|
||||||
{
|
{
|
||||||
|
@ -150,6 +67,8 @@ public:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::vector<Entry>::iterator begin() {return m_entries.begin();}
|
||||||
|
inline std::vector<Entry>::iterator end() {return m_entries.end();}
|
||||||
inline size_t getDataOffset() const {return m_dataOffset;}
|
inline size_t getDataOffset() const {return m_dataOffset;}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,34 +5,41 @@ namespace Retro
|
||||||
|
|
||||||
LogVisor::LogModule LogModule("RetroDataSpec");
|
LogVisor::LogModule LogModule("RetroDataSpec");
|
||||||
|
|
||||||
bool SpecBase::canExtract(const ExtractPassInfo& info)
|
bool SpecBase::canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps)
|
||||||
{
|
{
|
||||||
bool isWii;
|
bool isWii;
|
||||||
std::unique_ptr<NOD::DiscBase> disc = NOD::OpenDiscFromImage(info.srcpath.c_str(), isWii);
|
std::unique_ptr<NOD::DiscBase> disc = NOD::OpenDiscFromImage(info.srcpath->c_str(), isWii);
|
||||||
if (!disc)
|
if (!disc)
|
||||||
{
|
{
|
||||||
LogModule.report(LogVisor::Error, _S("'%s' not a valid Nintendo disc image"), info.srcpath.c_str());
|
LogModule.report(LogVisor::Error, _S("'%s' not a valid Nintendo disc image"), info.srcpath->c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const char* gameID = disc->getHeader().gameID;
|
const char* gameID = disc->getHeader().gameID;
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
if (isWii)
|
if (isWii)
|
||||||
{
|
{
|
||||||
if (!memcmp(gameID, "R3ME01", 6))
|
if (!memcmp(gameID, "R3M", 3))
|
||||||
return true;
|
valid = true;
|
||||||
if (!memcmp(gameID, "R3MP01", 6))
|
else if (!memcmp(gameID, "R3IJ01", 6))
|
||||||
return true;
|
valid = true;
|
||||||
if (!memcmp(gameID, "R3IJ01", 6))
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!memcmp(gameID, "GM8E01", 6))
|
if (!memcmp(gameID, "GM8", 3))
|
||||||
return true;
|
valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogModule.report(LogVisor::Error, "%.6s (%s) is not supported", gameID, disc->getHeader().gameTitle);
|
if (!valid)
|
||||||
return false;
|
{
|
||||||
|
LogModule.report(LogVisor::Error, "%.6s (%s) is not supported", gameID, disc->getHeader().gameTitle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isWii)
|
||||||
|
return checkFromWiiDisc(*(NOD::DiscWii*)disc.get(), info.extractArgs, reps);
|
||||||
|
else
|
||||||
|
return checkFromGCNDisc(*(NOD::DiscGCN*)disc.get(), info.extractArgs, reps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpecBase::doExtract(const HECL::Database::Project& project, const ExtractPassInfo& info)
|
void SpecBase::doExtract(const HECL::Database::Project& project, const ExtractPassInfo& info)
|
||||||
|
|
|
@ -13,7 +13,7 @@ extern LogVisor::LogModule LogModule;
|
||||||
|
|
||||||
struct SpecBase : HECL::Database::IDataSpec
|
struct SpecBase : HECL::Database::IDataSpec
|
||||||
{
|
{
|
||||||
bool canExtract(const ExtractPassInfo& info);
|
bool canExtract(const ExtractPassInfo& info, std::vector<ExtractReport>& reps);
|
||||||
void doExtract(const HECL::Database::Project& project, const ExtractPassInfo& info);
|
void doExtract(const HECL::Database::Project& project, const ExtractPassInfo& info);
|
||||||
|
|
||||||
bool canCook(const HECL::Database::Project& project, const CookTaskInfo& info);
|
bool canCook(const HECL::Database::Project& project, const CookTaskInfo& info);
|
||||||
|
@ -24,11 +24,13 @@ struct SpecBase : HECL::Database::IDataSpec
|
||||||
std::unordered_set<HECL::ProjectPath>& implicitsOut);
|
std::unordered_set<HECL::ProjectPath>& implicitsOut);
|
||||||
void doPackage(const HECL::Database::Project& project, const PackagePassInfo& info);
|
void doPackage(const HECL::Database::Project& project, const PackagePassInfo& info);
|
||||||
|
|
||||||
virtual bool checkFromGCNDisc(NOD::DiscGCN& disc, ExtractOption& opts)=0;
|
virtual bool checkFromGCNDisc(NOD::DiscGCN& disc, const std::vector<const HECL::SystemString*>& args,
|
||||||
virtual bool readFromGCNDisc(NOD::DiscGCN& disc)=0;
|
std::vector<ExtractReport>& reps)=0;
|
||||||
|
virtual bool readFromGCNDisc(NOD::DiscGCN& disc, const std::vector<const HECL::SystemString*>& args)=0;
|
||||||
|
|
||||||
virtual bool checkFromWiiDisc(NOD::DiscWii& disc, ExtractOption& opts)=0;
|
virtual bool checkFromWiiDisc(NOD::DiscWii& disc, const std::vector<const HECL::SystemString*>& args,
|
||||||
virtual bool readFromWiiDisc(NOD::DiscWii& disc)=0;
|
std::vector<ExtractReport>& reps)=0;
|
||||||
|
virtual bool readFromWiiDisc(NOD::DiscWii& disc, const std::vector<const HECL::SystemString*>& args)=0;
|
||||||
|
|
||||||
virtual bool checkFromProject(HECL::Database::Project& proj)=0;
|
virtual bool checkFromProject(HECL::Database::Project& proj)=0;
|
||||||
virtual bool readFromProject(HECL::Database::Project& proj)=0;
|
virtual bool readFromProject(HECL::Database::Project& proj)=0;
|
||||||
|
|
|
@ -3,54 +3,163 @@
|
||||||
#define NOD_ATHENA 1
|
#define NOD_ATHENA 1
|
||||||
#include "SpecBase.hpp"
|
#include "SpecBase.hpp"
|
||||||
#include "DNAMP1/PAK.hpp"
|
#include "DNAMP1/PAK.hpp"
|
||||||
|
#include "DNAMP1/MLVL.hpp"
|
||||||
|
#include "DNAMP1/STRG.hpp"
|
||||||
|
|
||||||
namespace Retro
|
namespace Retro
|
||||||
{
|
{
|
||||||
|
|
||||||
struct SpecMP1 : SpecBase
|
struct SpecMP1 : SpecBase
|
||||||
{
|
{
|
||||||
std::map<std::string, std::pair<std::string, DNAMP1::PAK>> m_worldPaks;
|
std::vector<std::pair<std::string, DNAMP1::PAK>> m_paks;
|
||||||
|
|
||||||
bool checkFromGCNDisc(NOD::DiscGCN& disc, ExtractOption& opts)
|
bool checkFromGCNDisc(NOD::DiscGCN& disc,
|
||||||
|
const std::vector<const HECL::SystemString*>& args,
|
||||||
|
std::vector<ExtractReport>& reps)
|
||||||
{
|
{
|
||||||
if (memcmp(disc.getHeader().gameID, "GM8", 3))
|
if (memcmp(disc.getHeader().gameID, "GM8", 3))
|
||||||
return false;
|
return false;
|
||||||
|
char region = disc.getHeader().gameID[3];
|
||||||
|
static const std::string regNONE = "";
|
||||||
|
static const std::string regE = "NTSC";
|
||||||
|
static const std::string regJ = "NTSC-J";
|
||||||
|
static const std::string regP = "PAL";
|
||||||
|
const std::string* regstr = ®NONE;
|
||||||
|
switch (region)
|
||||||
|
{
|
||||||
|
case 'E':
|
||||||
|
regstr = ®E;
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
regstr = ®J;
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
regstr = ®P;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NOD::DiscGCN::IPartition* partition = disc.getDataPartition();
|
||||||
|
std::unique_ptr<uint8_t[]> dolBuf = partition->getDOLBuf();
|
||||||
|
const char* buildInfo = (char*)memmem(dolBuf.get(), partition->getDOLSize(), "MetroidBuildInfo", 16) + 16;
|
||||||
|
|
||||||
|
reps.emplace_back();
|
||||||
|
ExtractReport& rep = reps.back();
|
||||||
|
rep.name = "MP1";
|
||||||
|
rep.desc = "Metroid Prime " + *regstr;
|
||||||
|
if (buildInfo)
|
||||||
|
rep.desc += " (" + std::string(buildInfo) + ")";
|
||||||
|
|
||||||
/* Iterate PAKs and build level options */
|
/* Iterate PAKs and build level options */
|
||||||
m_worldPaks.clear();
|
std::map<std::string, std::pair<const NOD::DiscBase::IPartition::Node*, DNAMP1::PAK*>,
|
||||||
|
CaseInsensitiveCompare> orderedPaks;
|
||||||
NOD::DiscBase::IPartition::Node& root = disc.getDataPartition()->getFSTRoot();
|
NOD::DiscBase::IPartition::Node& root = disc.getDataPartition()->getFSTRoot();
|
||||||
for (const NOD::DiscBase::IPartition::Node& child : root)
|
for (const NOD::DiscBase::IPartition::Node& child : root)
|
||||||
{
|
{
|
||||||
std::string name = child.getName();
|
const std::string& name = child.getName();
|
||||||
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
std::string lowerName = name;
|
||||||
if (!name.compare(0, 7, "metroid") && !name.compare(8, 4, ".pak"))
|
std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower);
|
||||||
|
if (name.size() > 4)
|
||||||
{
|
{
|
||||||
/* This is a world pak */
|
std::string::iterator extit = lowerName.end() - 4;
|
||||||
std::pair<std::map<std::string, std::pair<std::string, DNAMP1::PAK>>::iterator,bool> res =
|
if (!std::string(extit, lowerName.end()).compare(".pak"))
|
||||||
m_worldPaks.emplace(std::make_pair(name, std::make_pair(child.getName(), DNAMP1::PAK())));
|
|
||||||
if (res.second)
|
|
||||||
{
|
{
|
||||||
NOD::AthenaPartReadStream rs(child.beginReadStream());
|
/* This is a pak */
|
||||||
res.first->second.second.read(rs);
|
std::string lowerBase(lowerName.begin(), extit);
|
||||||
|
|
||||||
|
/* Needs filter */
|
||||||
|
bool good = true;
|
||||||
|
if (args.size())
|
||||||
|
{
|
||||||
|
good = false;
|
||||||
|
if (!lowerName.compare(0, 7, "metroid"))
|
||||||
|
{
|
||||||
|
HECL::SystemChar idxChar = lowerName[7];
|
||||||
|
for (const HECL::SystemString* arg : args)
|
||||||
|
{
|
||||||
|
if (arg->size() == 1 && iswdigit((*arg)[0]))
|
||||||
|
if ((*arg)[0] == idxChar)
|
||||||
|
good = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!good)
|
||||||
|
{
|
||||||
|
for (const HECL::SystemString* arg : args)
|
||||||
|
{
|
||||||
|
#if HECL_UCS2
|
||||||
|
std::string lowerArg = HECL::WideToUTF8(*arg);
|
||||||
|
#else
|
||||||
|
std::string lowerArg = *arg;
|
||||||
|
#endif
|
||||||
|
std::transform(lowerArg.begin(), lowerArg.end(), lowerArg.begin(), tolower);
|
||||||
|
if (!lowerArg.compare(0, lowerBase.size(), lowerBase))
|
||||||
|
good = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (good)
|
||||||
|
{
|
||||||
|
m_paks.emplace_back(std::make_pair(name, DNAMP1::PAK()));
|
||||||
|
std::pair<std::string, DNAMP1::PAK>& res = m_paks.back();
|
||||||
|
NOD::AthenaPartReadStream rs(child.beginReadStream());
|
||||||
|
res.second.read(rs);
|
||||||
|
orderedPaks[name] = std::make_pair(&child, &res.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::pair<std::string, std::pair<const NOD::DiscBase::IPartition::Node*, DNAMP1::PAK*>> item : orderedPaks)
|
||||||
|
{
|
||||||
|
rep.childOpts.emplace_back();
|
||||||
|
ExtractReport& childRep = rep.childOpts.back();
|
||||||
|
childRep.name = item.first;
|
||||||
|
|
||||||
|
for (DNAMP1::PAK::Entry& entry : *item.second.second)
|
||||||
|
{
|
||||||
|
static const HECL::FourCC MLVLfourcc("MLVL");
|
||||||
|
if (entry.type == MLVLfourcc)
|
||||||
|
{
|
||||||
|
NOD::AthenaPartReadStream rs(item.second.first->beginReadStream(entry.offset));
|
||||||
|
DNAMP1::MLVL mlvl;
|
||||||
|
mlvl.read(rs);
|
||||||
|
const DNAMP1::PAK::Entry* nameEnt = item.second.second->lookupEntry(mlvl.worldNameId);
|
||||||
|
if (nameEnt)
|
||||||
|
{
|
||||||
|
DNAMP1::STRG mlvlName;
|
||||||
|
rs.seek(nameEnt->offset, Athena::Begin);
|
||||||
|
mlvlName.read(rs);
|
||||||
|
if (childRep.desc.size())
|
||||||
|
childRep.desc += _S(", ");
|
||||||
|
#if HECL_UCS2
|
||||||
|
childRep.desc += mlvlName.langs[0].strings[0];
|
||||||
|
#else
|
||||||
|
childRep.desc += HECL::WideToUTF8(mlvlName.langs[0].strings[0]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool readFromGCNDisc(NOD::DiscGCN& disc)
|
bool readFromGCNDisc(NOD::DiscGCN& disc,
|
||||||
|
const std::vector<const HECL::SystemString*>& args)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkFromWiiDisc(NOD::DiscWii& disc, ExtractOption& opts)
|
bool checkFromWiiDisc(NOD::DiscWii& disc,
|
||||||
|
const std::vector<const HECL::SystemString*>& args,
|
||||||
|
std::vector<ExtractReport>& reps)
|
||||||
{
|
{
|
||||||
if (memcmp(disc.getHeader().gameID, "R3M", 3))
|
if (memcmp(disc.getHeader().gameID, "R3M", 3))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool readFromWiiDisc(NOD::DiscWii& disc)
|
bool readFromWiiDisc(NOD::DiscWii& disc,
|
||||||
|
const std::vector<const HECL::SystemString*>& args)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
NODLib
2
NODLib
|
@ -1 +1 @@
|
||||||
Subproject commit b6969a82dc0b486240302092c41d6a0596d89777
|
Subproject commit b8236ba6d749e20411345fd276d4e4aec98256de
|
Loading…
Reference in New Issue