aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/loader
diff options
context:
space:
mode:
authorGravatar Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>2015-01-06 23:10:13 +0000
committerGravatar Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>2015-01-15 22:23:08 +0100
commit82ec17db7df53ed1c376d1cdaa9a6587719a546d (patch)
tree3c2236849146037fbba2fb75ea8a50f53b847a17 /src/core/loader
parent04622a859cc748745cbbeb0b332f930085438077 (diff)
Loader: Guess filetype from the magic, or fallback to the extension.
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/3dsx.cpp13
-rw-r--r--src/core/loader/3dsx.h7
-rw-r--r--src/core/loader/elf.cpp12
-rw-r--r--src/core/loader/elf.h7
-rw-r--r--src/core/loader/loader.cpp60
-rw-r--r--src/core/loader/loader.h11
-rw-r--r--src/core/loader/ncch.cpp19
-rw-r--r--src/core/loader/ncch.h9
8 files changed, 112 insertions, 26 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index e239808f..f3e09ecd 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -44,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
{
@@ -202,6 +201,18 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
return ERROR_NONE;
}
+FileType AppLoader_THREEDSX::IdentifyType(FileUtil::IOFile& file) {
+ u32 magic;
+ file.Seek(0, SEEK_SET);
+ if (1 != file.ReadArray<u32>(&magic, 1))
+ return FileType::Error;
+
+ if (MakeMagic('3', 'D', 'S', 'X') == magic)
+ return FileType::THREEDSX;
+
+ return FileType::Error;
+}
+
ResultStatus AppLoader_THREEDSX::Load() {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index 2f2e8bec..a1166740 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -18,6 +18,13 @@ public:
AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
/**
+ * Returns the type of the file
+ * @param file FileUtil::IOFile open file
+ * @return FileType found, or FileType::Error if this loader doesn't know it
+ */
+ static FileType IdentifyType(FileUtil::IOFile& file);
+
+ /**
* Load the bootable file
* @return ResultStatus result of function
*/
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 712d564d..d1c3aea7 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -330,6 +330,18 @@ bool ElfReader::LoadSymbols() {
namespace Loader {
+FileType AppLoader_ELF::IdentifyType(FileUtil::IOFile& file) {
+ u32 magic;
+ file.Seek(0, SEEK_SET);
+ if (1 != file.ReadArray<u32>(&magic, 1))
+ return FileType::Error;
+
+ if (MakeMagic('\x7f', 'E', 'L', 'F') == magic)
+ return FileType::ELF;
+
+ return FileType::Error;
+}
+
ResultStatus AppLoader_ELF::Load() {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 1c476c86..b6e6651f 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -18,6 +18,13 @@ public:
AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
/**
+ * Returns the type of the file
+ * @param file FileUtil::IOFile open file
+ * @return FileType found, or FileType::Error if this loader doesn't know it
+ */
+ static FileType IdentifyType(FileUtil::IOFile& file);
+
+ /**
* Load the bootable file
* @return ResultStatus result of function
*/
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index fd32b7b2..01b41521 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -19,11 +19,32 @@ namespace Loader {
/**
* Identifies the type of a bootable file
+ * @param file open file
+ * @return FileType of file
+ */
+static FileType IdentifyFile(FileUtil::IOFile& file) {
+ FileType type;
+
+#define CHECK_TYPE(loader) \
+ type = AppLoader_##loader::IdentifyType(file); \
+ if (FileType::Error != type) \
+ return type;
+
+ CHECK_TYPE(THREEDSX)
+ CHECK_TYPE(ELF)
+ CHECK_TYPE(NCCH)
+
+#undef CHECK_TYPE
+
+ return FileType::Unknown;
+}
+
+/**
+ * Guess the type of a bootable file from its extension
* @param filename String filename of bootable file
- * @todo (ShizZy) this function sucks... make it actually check file contents etc.
* @return FileType of file
*/
-FileType IdentifyFile(const std::string &filename) {
+static FileType GuessFromFilename(const std::string& filename) {
if (filename.size() == 0) {
LOG_ERROR(Loader, "invalid filename %s", filename.c_str());
return FileType::Error;
@@ -34,22 +55,20 @@ FileType IdentifyFile(const std::string &filename) {
return FileType::Unknown;
std::string extension = Common::ToLower(filename.substr(extension_loc));
- // TODO(bunnei): Do actual filetype checking instead of naively checking the extension
- if (extension == ".elf") {
+ if (extension == ".elf")
return FileType::ELF;
- } else if (extension == ".axf") {
+ else if (extension == ".axf")
return FileType::ELF;
- } else if (extension == ".cxi") {
+ else if (extension == ".cxi")
return FileType::CXI;
- } else if (extension == ".cci") {
+ else if (extension == ".cci")
return FileType::CCI;
- } else if (extension == ".bin") {
+ else if (extension == ".bin")
return FileType::BIN;
- } else if (extension == ".3ds") {
+ else if (extension == ".3ds")
return FileType::CCI;
- } else if (extension == ".3dsx") {
+ else if (extension == ".3dsx")
return FileType::THREEDSX;
- }
return FileType::Unknown;
}
@@ -60,7 +79,16 @@ ResultStatus LoadFile(const std::string& filename) {
if (!file->IsOpen())
return ResultStatus::Error;
- switch (IdentifyFile(filename)) {
+ FileType type = IdentifyFile(*file);
+ FileType filename_type = GuessFromFilename(filename);
+
+ if (type != filename_type) {
+ LOG_WARNING(Loader, "File %s has a different type than its extension.", filename.c_str());
+ if (FileType::Unknown == type)
+ type = filename_type;
+ }
+
+ switch (type) {
//3DSX file format...
case FileType::THREEDSX:
@@ -72,7 +100,8 @@ ResultStatus LoadFile(const std::string& filename) {
// NCCH/NCSD container formats...
case FileType::CXI:
- case FileType::CCI: {
+ case FileType::CCI:
+ {
AppLoader_NCCH app_loader(std::move(file));
// Load application and RomFS
@@ -100,10 +129,11 @@ ResultStatus LoadFile(const std::string& filename) {
// IdentifyFile could know identify file type...
case FileType::Unknown:
-
- default:
+ {
+ LOG_CRITICAL(Loader, "File %s is of unknown type.");
return ResultStatus::ErrorInvalidFormat;
}
+ }
return ResultStatus::Error;
}
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index b4fc8636..7456b019 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -38,6 +38,10 @@ enum class ResultStatus {
ErrorMemoryAllocationFailed,
};
+static u32 MakeMagic(char a, char b, char c, char d) {
+ return a | b << 8 | c << 16 | d << 24;
+}
+
/// Interface for loading an application
class AppLoader : NonCopyable {
public:
@@ -101,13 +105,6 @@ protected:
};
/**
- * Identifies the type of a bootable file
- * @param filename String filename of bootable file
- * @return FileType of file
- */
-FileType IdentifyFile(const std::string &filename);
-
-/**
* Identifies and loads a bootable file
* @param filename String filename of bootable file
* @return ResultStatus result of function
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index edf53c2c..d6eb549b 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -97,6 +97,21 @@ static bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompresse
////////////////////////////////////////////////////////////////////////////////////////////////////
// AppLoader_NCCH class
+FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
+ u32 magic;
+ file.Seek(0x100, SEEK_SET);
+ if (1 != file.ReadArray<u32>(&magic, 1))
+ return FileType::Error;
+
+ if (MakeMagic('N', 'C', 'S', 'D') == magic)
+ return FileType::CCI;
+
+ if (MakeMagic('N', 'C', 'C', 'H') == magic)
+ return FileType::CXI;
+
+ return FileType::Error;
+}
+
ResultStatus AppLoader_NCCH::LoadExec() const {
if (!is_loaded)
return ResultStatus::ErrorNotLoaded;
@@ -171,7 +186,7 @@ ResultStatus AppLoader_NCCH::Load() {
file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
// Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
- if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
+ if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) {
LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
ncch_offset = 0x4000;
file->Seek(ncch_offset, SEEK_SET);
@@ -179,7 +194,7 @@ ResultStatus AppLoader_NCCH::Load() {
}
// Verify we are loading the correct file type...
- if (0 != memcmp(&ncch_header.magic, "NCCH", 4))
+ if (MakeMagic('N', 'C', 'C', 'H') != ncch_header.magic)
return ResultStatus::ErrorInvalidFormat;
// Read ExHeader...
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index d9d68f15..9ae2de99 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -13,7 +13,7 @@
struct NCCH_Header {
u8 signature[0x100];
- char magic[4];
+ u32 magic;
u32 content_size;
u8 partition_id[8];
u16 maker_code;
@@ -149,6 +149,13 @@ public:
AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
/**
+ * Returns the type of the file
+ * @param file FileUtil::IOFile open file
+ * @return FileType found, or FileType::Error if this loader doesn't know it
+ */
+ static FileType IdentifyType(FileUtil::IOFile& file);
+
+ /**
* Load the application
* @return ResultStatus result of function
*/