aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/loader/3dsx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader/3dsx.cpp')
-rw-r--r--src/core/loader/3dsx.cpp109
1 files changed, 56 insertions, 53 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 4d072871..958dd03e 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -13,11 +13,9 @@
#include "3dsx.h"
-
namespace Loader {
-
-/**
+/**
* File layout:
* - File header
* - Code, rodata and data relocation table headers
@@ -46,7 +44,6 @@ enum THREEDSX_Error {
static const u32 RELOCBUFSIZE = 512;
// File header
-static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX'
#pragma pack(1)
struct THREEDSX_Header
{
@@ -64,9 +61,9 @@ struct THREEDSX_Header
struct THREEDSX_RelocHdr
{
// # of absolute relocations (that is, fix address to post-relocation memory layout)
- u32 cross_segment_absolute;
+ u32 cross_segment_absolute;
// # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched)
- u32 cross_segment_relative;
+ u32 cross_segment_relative;
// more?
// Relocations are written in this order:
@@ -88,12 +85,7 @@ struct THREEloadinfo
u32 seg_sizes[3];
};
-class THREEDSXReader {
-public:
- static int Load3DSXFile(const std::string& filename, u32 base_addr);
-};
-
-static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets)
+static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets)
{
if (addr < offsets[0])
return loadinfo->seg_addrs[0] + addr;
@@ -102,12 +94,14 @@ static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets)
return loadinfo->seg_addrs[2] + addr - offsets[1];
}
-int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
+static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
{
- FileUtil::IOFile file(filename, "rb");
- if (!file.IsOpen()) {
+ if (!file.IsOpen())
return ERROR_FILE;
- }
+
+ // Reset read pointer in case this file has been read before.
+ file.Seek(0, SEEK_SET);
+
THREEDSX_Header hdr;
if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr))
return ERROR_READ;
@@ -136,8 +130,9 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
// Read the relocation headers
u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size);
- for (u32 current_segment = 0; current_segment < 3; current_segment++) {
- if (file.ReadBytes(&relocs[current_segment*n_reloc_tables], n_reloc_tables * 4) != n_reloc_tables * 4)
+ for (unsigned current_segment : {0, 1, 2}) {
+ size_t size = n_reloc_tables * 4;
+ if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size)
return ERROR_READ;
}
@@ -153,9 +148,9 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
// Relocate the segments
- for (u32 current_segment = 0; current_segment < 3; current_segment++) {
- for (u32 current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
- u32 n_relocs = relocs[current_segment*n_reloc_tables + current_segment_reloc_table];
+ for (unsigned current_segment : {0, 1, 2}) {
+ for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
+ u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table];
if (current_segment_reloc_table >= 2) {
// We are not using this table - ignore it because we don't know what it dose
file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
@@ -164,29 +159,35 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
static THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
- u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
+ const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
while (n_relocs) {
u32 remaining = std::min(RELOCBUFSIZE, n_relocs);
n_relocs -= remaining;
- if (file.ReadBytes(reloc_table, remaining*sizeof(THREEDSX_Reloc)) != remaining*sizeof(THREEDSX_Reloc))
+ if (file.ReadBytes(reloc_table, remaining * sizeof(THREEDSX_Reloc)) != remaining * sizeof(THREEDSX_Reloc))
return ERROR_READ;
- for (u32 current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) {
- LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n",
- current_segment_reloc_table, (u32)reloc_table[current_inprogress].skip, (u32)reloc_table[current_inprogress].patch);
- pos += reloc_table[current_inprogress].skip;
- s32 num_patches = reloc_table[current_inprogress].patch;
+ for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) {
+ const auto& table = reloc_table[current_inprogress];
+ LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n", current_segment_reloc_table,
+ (u32)table.skip, (u32)table.patch);
+ pos += table.skip;
+ s32 num_patches = table.patch;
while (0 < num_patches && pos < end_pos) {
u32 in_addr = (char*)pos - (char*)&all_mem[0];
u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
- base_addr + in_addr, addr, current_segment_reloc_table, *pos);
+ base_addr + in_addr, addr, current_segment_reloc_table, *pos);
switch (current_segment_reloc_table) {
- case 0: *pos = (addr); break;
- case 1: *pos = (addr - in_addr); break;
- default: break; //this should never happen
+ case 0:
+ *pos = (addr);
+ break;
+ case 1:
+ *pos = (addr - in_addr);
+ break;
+ default:
+ break; //this should never happen
}
pos++;
num_patches--;
@@ -207,28 +208,30 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
return ERROR_NONE;
}
- /// AppLoader_DSX constructor
- AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) {
- }
+FileType AppLoader_THREEDSX::IdentifyType(FileUtil::IOFile& file) {
+ u32 magic;
+ file.Seek(0, SEEK_SET);
+ if (1 != file.ReadArray<u32>(&magic, 1))
+ return FileType::Error;
- /// AppLoader_DSX destructor
- AppLoader_THREEDSX::~AppLoader_THREEDSX() {
- }
+ if (MakeMagic('3', 'D', 'S', 'X') == magic)
+ return FileType::THREEDSX;
- /**
- * Loads a 3DSX file
- * @return Success on success, otherwise Error
- */
- ResultStatus AppLoader_THREEDSX::Load() {
- LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str());
- FileUtil::IOFile file(filename, "rb");
- if (file.IsOpen()) {
- THREEDSXReader::Load3DSXFile(filename, 0x00100000);
- Kernel::LoadExec(0x00100000);
- } else {
- return ResultStatus::Error;
- }
- return ResultStatus::Success;
- }
+ return FileType::Error;
+}
+
+ResultStatus AppLoader_THREEDSX::Load() {
+ if (is_loaded)
+ return ResultStatus::ErrorAlreadyLoaded;
+
+ if (!file->IsOpen())
+ return ResultStatus::Error;
+
+ Load3DSXFile(*file, 0x00100000);
+ Kernel::LoadExec(0x00100000);
+
+ is_loaded = true;
+ return ResultStatus::Success;
+}
} // namespace Loader