Compare commits

...

1 Commits

Author SHA1 Message Date
SuperDude88 529a61001a RPX Loader
This is mostly a mess and should not be included in its current state, pushing it so I don't forget/lose it on my machine. Only changes Link's l_sightDL as a (messy) example since the other cases probably need further code changes.

Does not currently support multiple RPX versions/regions. Handling of SD/HD switching should be fleshed out more before integrating this fully imo.
2026-06-25 23:09:28 -04:00
3 changed files with 185 additions and 1 deletions
+7
View File
@@ -28,4 +28,11 @@ bool LoadRelAsset(void* dst, const char* dvdPath, std::initializer_list<OffsetVe
*/ */
bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list<OffsetVersion> offset, s32 size); bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list<OffsetVersion> offset, s32 size);
#ifdef DUSK_TPHD
/**
* Load bytes from the RPX by Wii U virtual address
*/
bool LoadRPXAsset(void* dst, uint32_t virtualAddress, s32 size);
#endif
} // namespace dusk } // namespace dusk
+32 -1
View File
@@ -371,11 +371,41 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() {
#include "dusk/dvd_asset.hpp" #include "dusk/dvd_asset.hpp"
using GameVersion = dusk::version::GameVersion; using GameVersion = dusk::version::GameVersion;
static const u8* l_sightDL_get() { static const u8* l_sightDL_get() {
#if DUSK_TPHD
if(dusk::tphd_active()) {
static u8 buf[0x89];
static bool _ = (
dusk::LoadRPXAsset(
buf,
0x1011a260,
0x89
),
true
);
return buf;
}
else {
static u8 buf[0x89];
static bool _ = (
dusk::LoadDolAsset(
buf,
{
{GameVersion::GcnUsa, 0x803BA0C0},
{GameVersion::GcnPal, 0x803BBDA0},
{GameVersion::GcnJpn, 0x803B4220}
},
0x89
),
true
);
return buf;
}
#else
static u8 buf[0x89]; static u8 buf[0x89];
static bool _ = ( static bool _ = (
dusk::LoadDolAsset( dusk::LoadDolAsset(
buf, buf,
{ {
{GameVersion::GcnUsa, 0x803BA0C0}, {GameVersion::GcnUsa, 0x803BA0C0},
{GameVersion::GcnPal, 0x803BBDA0}, {GameVersion::GcnPal, 0x803BBDA0},
{GameVersion::GcnJpn, 0x803B4220} {GameVersion::GcnJpn, 0x803B4220}
@@ -385,6 +415,7 @@ static const u8* l_sightDL_get() {
true true
); );
return buf; return buf;
#endif
} }
#define l_sightDL (l_sightDL_get()) #define l_sightDL (l_sightDL_get())
#else #else
+146
View File
@@ -8,6 +8,11 @@
#include <cstring> #include <cstring>
#ifdef DUSK_TPHD
#include <zlib.h>
#include <fstream>
#endif
namespace dusk { namespace dusk {
static const u8* s_dolData = nullptr; // pointer to dol data static const u8* s_dolData = nullptr; // pointer to dol data
@@ -136,4 +141,145 @@ bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::
return true; return true;
} }
#ifdef DUSK_TPHD
enum struct SectionType : uint32_t // sh_type
{
// https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
SHT_NULL = 0,
SHT_PROGBITS = 1,
SHT_SYMTAB = 2,
SHT_STRTAB = 3,
SHT_RELA = 4,
SHT_HASH = 5,
SHT_DYNAMIC = 6,
SHT_NOTE = 7,
SHT_NOBITS = 8,
SHT_REL = 9,
SHT_SHLIB = 10,
SHT_DYNSYM = 11,
SHT_INIT_ARRAY = 14,
SHT_FINI_ARRAY = 15,
SHT_PREINIT_ARRAY = 16,
SHT_GROUP = 17,
SHT_SYMTAB_SHNDX = 18,
// https://refspecs.linuxfoundation.org/LSB_2.1.0/LSB-Core-generic/LSB-Core-generic/elftypes.html
SHT_LOPROC = 0x70000000,
SHT_HIPROC = 0x7fffffff,
SHT_LOUSER = 0x80000000,
SHT_HIUSER = 0xffffffff,
// from https://gist.github.com/exjam/b4290ad23828cbc04db4 and looking at the rpx itself
SHT_RPL_EXPORTS = 0x80000001,
SHT_RPL_IMPORTS = 0x80000002,
SHT_RPL_CRCS = 0x80000003,
SHT_RPL_FILEINFO = 0x80000004
};
enum struct SectionFlags : uint32_t {
// https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
// from https://gist.github.com/exjam/b4290ad23828cbc04db4 and looking at the rpx itself
SHF_DEFLATED = 0x08000000
};
struct Elf32_Ehdr {
uint8_t e_ident[0x10];
BE(u16) e_type;
BE(u16) e_machine;
BE(u32) e_version;
BE(u32) e_entry;
BE(u32) e_phoff;
BE(u32) e_shoff;
BE(u32) e_flags;
BE(u16) e_ehsize;
BE(u16) e_phentsize;
BE(u16) e_phnum;
BE(u16) e_shentsize;
BE(u16) e_shnum;
BE(u16) e_shstrndx;
};
struct Elf32_Shdr {
BE(u32) sh_name;
BE(u32) sh_type; // SectionType
BE(u32) sh_flags;
BE(u32) sh_addr;
BE(u32) sh_offset;
BE(u32) sh_size;
BE(u32) sh_link;
BE(u32) sh_info;
BE(u32) sh_addralign;
BE(u32) sh_entsize;
};
struct RPXSection {
u32 vaddr;
std::string data;
};
static std::vector<RPXSection> g_rpxSections;
static bool EnsureRPXParsed() {
if (!g_rpxSections.empty()) return true;
std::ifstream rpx(dusk::tphd_content_path().parent_path() / "code" / "Zelda.rpx", std::ios::binary);
if (!rpx.is_open()) {
DuskLog.fatal("dvd_asset: Failed to open Zelda.rpx");
return false;
}
Elf32_Ehdr ehdr;
rpx.read(reinterpret_cast<char*>(&ehdr), sizeof(ehdr));
for (int i = 0; i < ehdr.e_shnum; i++) {
rpx.seekg(ehdr.e_shoff + ehdr.e_shentsize * i, std::ios::beg);
Elf32_Shdr shdr;
rpx.read(reinterpret_cast<char*>(&shdr), sizeof(shdr));
if(shdr.sh_addr != 0 && shdr.sh_offset != 0 && (shdr.sh_type & ((int)SectionType::SHT_NULL | (int)SectionType::SHT_NOBITS)) == 0) {
rpx.seekg(shdr.sh_offset, std::ios::beg);
RPXSection& section = g_rpxSections.emplace_back();
section.vaddr = shdr.sh_addr;
if(shdr.sh_flags & (int)SectionFlags::SHF_DEFLATED) {
BE(u32) size;
std::string inData(shdr.sh_size - 4, '\0');
rpx.read(reinterpret_cast<char*>(&size), sizeof(size));
rpx.read(inData.data(), inData.size());
section.data.resize(size);
unsigned long outSize = section.data.size();
uncompress(reinterpret_cast<unsigned char*>(section.data.data()), &outSize, reinterpret_cast<unsigned char*>(inData.data()), inData.size());
}
else {
section.data.resize(shdr.sh_size);
rpx.read(section.data.data(), section.data.size());
}
}
}
return true;
}
bool LoadRPXAsset(void* dst, uint32_t virtualAddress, s32 size) {
if(!EnsureRPXParsed()) return false;
const auto& it = std::ranges::find_if(g_rpxSections, [virtualAddress, size](const RPXSection& section) { return section.vaddr <= virtualAddress && virtualAddress + size <= section.vaddr + section.data.size(); });
if(it == g_rpxSections.end()) {
return false;
}
it->data.copy(static_cast<char*>(dst), size, virtualAddress - it->vaddr);
return true;
}
#endif
} // namespace dusk } // namespace dusk