summaryrefslogtreecommitdiff
path: root/src/core/loader
diff options
context:
space:
mode:
authorGravatar Emmanuel Gil Peyrot2015-01-06 23:10:13 +0000
committerGravatar Emmanuel Gil Peyrot2015-01-15 22:23:08 +0100
commit82ec17db7df53ed1c376d1cdaa9a6587719a546d (patch)
tree3c2236849146037fbba2fb75ea8a50f53b847a17 /src/core/loader
parentLoader: Don’t assume the file hasn’t been read before. (diff)
downloadyuzu-82ec17db7df53ed1c376d1cdaa9a6587719a546d.tar.gz
yuzu-82ec17db7df53ed1c376d1cdaa9a6587719a546d.tar.xz
yuzu-82ec17db7df53ed1c376d1cdaa9a6587719a546d.zip
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 e239808f3..f3e09ecd6 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -44,7 +44,6 @@ enum THREEDSX_Error {
44static const u32 RELOCBUFSIZE = 512; 44static const u32 RELOCBUFSIZE = 512;
45 45
46// File header 46// File header
47static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX'
48#pragma pack(1) 47#pragma pack(1)
49struct THREEDSX_Header 48struct THREEDSX_Header
50{ 49{
@@ -202,6 +201,18 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
202 return ERROR_NONE; 201 return ERROR_NONE;
203} 202}
204 203
204FileType AppLoader_THREEDSX::IdentifyType(FileUtil::IOFile& file) {
205 u32 magic;
206 file.Seek(0, SEEK_SET);
207 if (1 != file.ReadArray<u32>(&magic, 1))
208 return FileType::Error;
209
210 if (MakeMagic('3', 'D', 'S', 'X') == magic)
211 return FileType::THREEDSX;
212
213 return FileType::Error;
214}
215
205ResultStatus AppLoader_THREEDSX::Load() { 216ResultStatus AppLoader_THREEDSX::Load() {
206 if (is_loaded) 217 if (is_loaded)
207 return ResultStatus::ErrorAlreadyLoaded; 218 return ResultStatus::ErrorAlreadyLoaded;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index 2f2e8bec0..a11667400 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -18,6 +18,13 @@ public:
18 AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { } 18 AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
19 19
20 /** 20 /**
21 * Returns the type of the file
22 * @param file FileUtil::IOFile open file
23 * @return FileType found, or FileType::Error if this loader doesn't know it
24 */
25 static FileType IdentifyType(FileUtil::IOFile& file);
26
27 /**
21 * Load the bootable file 28 * Load the bootable file
22 * @return ResultStatus result of function 29 * @return ResultStatus result of function
23 */ 30 */
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 712d564d1..d1c3aea72 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -330,6 +330,18 @@ bool ElfReader::LoadSymbols() {
330 330
331namespace Loader { 331namespace Loader {
332 332
333FileType AppLoader_ELF::IdentifyType(FileUtil::IOFile& file) {
334 u32 magic;
335 file.Seek(0, SEEK_SET);
336 if (1 != file.ReadArray<u32>(&magic, 1))
337 return FileType::Error;
338
339 if (MakeMagic('\x7f', 'E', 'L', 'F') == magic)
340 return FileType::ELF;
341
342 return FileType::Error;
343}
344
333ResultStatus AppLoader_ELF::Load() { 345ResultStatus AppLoader_ELF::Load() {
334 if (is_loaded) 346 if (is_loaded)
335 return ResultStatus::ErrorAlreadyLoaded; 347 return ResultStatus::ErrorAlreadyLoaded;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 1c476c86b..b6e6651f5 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -18,6 +18,13 @@ public:
18 AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { } 18 AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
19 19
20 /** 20 /**
21 * Returns the type of the file
22 * @param file FileUtil::IOFile open file
23 * @return FileType found, or FileType::Error if this loader doesn't know it
24 */
25 static FileType IdentifyType(FileUtil::IOFile& file);
26
27 /**
21 * Load the bootable file 28 * Load the bootable file
22 * @return ResultStatus result of function 29 * @return ResultStatus result of function
23 */ 30 */
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index fd32b7b20..01b415215 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -19,11 +19,32 @@ namespace Loader {
19 19
20/** 20/**
21 * Identifies the type of a bootable file 21 * Identifies the type of a bootable file
22 * @param file open file
23 * @return FileType of file
24 */
25static FileType IdentifyFile(FileUtil::IOFile& file) {
26 FileType type;
27
28#define CHECK_TYPE(loader) \
29 type = AppLoader_##loader::IdentifyType(file); \
30 if (FileType::Error != type) \
31 return type;
32
33 CHECK_TYPE(THREEDSX)
34 CHECK_TYPE(ELF)
35 CHECK_TYPE(NCCH)
36
37#undef CHECK_TYPE
38
39 return FileType::Unknown;
40}
41
42/**
43 * Guess the type of a bootable file from its extension
22 * @param filename String filename of bootable file 44 * @param filename String filename of bootable file
23 * @todo (ShizZy) this function sucks... make it actually check file contents etc.
24 * @return FileType of file 45 * @return FileType of file
25 */ 46 */
26FileType IdentifyFile(const std::string &filename) { 47static FileType GuessFromFilename(const std::string& filename) {
27 if (filename.size() == 0) { 48 if (filename.size() == 0) {
28 LOG_ERROR(Loader, "invalid filename %s", filename.c_str()); 49 LOG_ERROR(Loader, "invalid filename %s", filename.c_str());
29 return FileType::Error; 50 return FileType::Error;
@@ -34,22 +55,20 @@ FileType IdentifyFile(const std::string &filename) {
34 return FileType::Unknown; 55 return FileType::Unknown;
35 std::string extension = Common::ToLower(filename.substr(extension_loc)); 56 std::string extension = Common::ToLower(filename.substr(extension_loc));
36 57
37 // TODO(bunnei): Do actual filetype checking instead of naively checking the extension 58 if (extension == ".elf")
38 if (extension == ".elf") {
39 return FileType::ELF; 59 return FileType::ELF;
40 } else if (extension == ".axf") { 60 else if (extension == ".axf")
41 return FileType::ELF; 61 return FileType::ELF;
42 } else if (extension == ".cxi") { 62 else if (extension == ".cxi")
43 return FileType::CXI; 63 return FileType::CXI;
44 } else if (extension == ".cci") { 64 else if (extension == ".cci")
45 return FileType::CCI; 65 return FileType::CCI;
46 } else if (extension == ".bin") { 66 else if (extension == ".bin")
47 return FileType::BIN; 67 return FileType::BIN;
48 } else if (extension == ".3ds") { 68 else if (extension == ".3ds")
49 return FileType::CCI; 69 return FileType::CCI;
50 } else if (extension == ".3dsx") { 70 else if (extension == ".3dsx")
51 return FileType::THREEDSX; 71 return FileType::THREEDSX;
52 }
53 return FileType::Unknown; 72 return FileType::Unknown;
54} 73}
55 74
@@ -60,7 +79,16 @@ ResultStatus LoadFile(const std::string& filename) {
60 if (!file->IsOpen()) 79 if (!file->IsOpen())
61 return ResultStatus::Error; 80 return ResultStatus::Error;
62 81
63 switch (IdentifyFile(filename)) { 82 FileType type = IdentifyFile(*file);
83 FileType filename_type = GuessFromFilename(filename);
84
85 if (type != filename_type) {
86 LOG_WARNING(Loader, "File %s has a different type than its extension.", filename.c_str());
87 if (FileType::Unknown == type)
88 type = filename_type;
89 }
90
91 switch (type) {
64 92
65 //3DSX file format... 93 //3DSX file format...
66 case FileType::THREEDSX: 94 case FileType::THREEDSX:
@@ -72,7 +100,8 @@ ResultStatus LoadFile(const std::string& filename) {
72 100
73 // NCCH/NCSD container formats... 101 // NCCH/NCSD container formats...
74 case FileType::CXI: 102 case FileType::CXI:
75 case FileType::CCI: { 103 case FileType::CCI:
104 {
76 AppLoader_NCCH app_loader(std::move(file)); 105 AppLoader_NCCH app_loader(std::move(file));
77 106
78 // Load application and RomFS 107 // Load application and RomFS
@@ -100,10 +129,11 @@ ResultStatus LoadFile(const std::string& filename) {
100 129
101 // IdentifyFile could know identify file type... 130 // IdentifyFile could know identify file type...
102 case FileType::Unknown: 131 case FileType::Unknown:
103 132 {
104 default: 133 LOG_CRITICAL(Loader, "File %s is of unknown type.");
105 return ResultStatus::ErrorInvalidFormat; 134 return ResultStatus::ErrorInvalidFormat;
106 } 135 }
136 }
107 return ResultStatus::Error; 137 return ResultStatus::Error;
108} 138}
109 139
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index b4fc8636d..7456b019b 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -38,6 +38,10 @@ enum class ResultStatus {
38 ErrorMemoryAllocationFailed, 38 ErrorMemoryAllocationFailed,
39}; 39};
40 40
41static u32 MakeMagic(char a, char b, char c, char d) {
42 return a | b << 8 | c << 16 | d << 24;
43}
44
41/// Interface for loading an application 45/// Interface for loading an application
42class AppLoader : NonCopyable { 46class AppLoader : NonCopyable {
43public: 47public:
@@ -101,13 +105,6 @@ protected:
101}; 105};
102 106
103/** 107/**
104 * Identifies the type of a bootable file
105 * @param filename String filename of bootable file
106 * @return FileType of file
107 */
108FileType IdentifyFile(const std::string &filename);
109
110/**
111 * Identifies and loads a bootable file 108 * Identifies and loads a bootable file
112 * @param filename String filename of bootable file 109 * @param filename String filename of bootable file
113 * @return ResultStatus result of function 110 * @return ResultStatus result of function
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index edf53c2c0..d6eb549b7 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
97//////////////////////////////////////////////////////////////////////////////////////////////////// 97////////////////////////////////////////////////////////////////////////////////////////////////////
98// AppLoader_NCCH class 98// AppLoader_NCCH class
99 99
100FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
101 u32 magic;
102 file.Seek(0x100, SEEK_SET);
103 if (1 != file.ReadArray<u32>(&magic, 1))
104 return FileType::Error;
105
106 if (MakeMagic('N', 'C', 'S', 'D') == magic)
107 return FileType::CCI;
108
109 if (MakeMagic('N', 'C', 'C', 'H') == magic)
110 return FileType::CXI;
111
112 return FileType::Error;
113}
114
100ResultStatus AppLoader_NCCH::LoadExec() const { 115ResultStatus AppLoader_NCCH::LoadExec() const {
101 if (!is_loaded) 116 if (!is_loaded)
102 return ResultStatus::ErrorNotLoaded; 117 return ResultStatus::ErrorNotLoaded;
@@ -171,7 +186,7 @@ ResultStatus AppLoader_NCCH::Load() {
171 file->ReadBytes(&ncch_header, sizeof(NCCH_Header)); 186 file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
172 187
173 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... 188 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
174 if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) { 189 if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) {
175 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!"); 190 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
176 ncch_offset = 0x4000; 191 ncch_offset = 0x4000;
177 file->Seek(ncch_offset, SEEK_SET); 192 file->Seek(ncch_offset, SEEK_SET);
@@ -179,7 +194,7 @@ ResultStatus AppLoader_NCCH::Load() {
179 } 194 }
180 195
181 // Verify we are loading the correct file type... 196 // Verify we are loading the correct file type...
182 if (0 != memcmp(&ncch_header.magic, "NCCH", 4)) 197 if (MakeMagic('N', 'C', 'C', 'H') != ncch_header.magic)
183 return ResultStatus::ErrorInvalidFormat; 198 return ResultStatus::ErrorInvalidFormat;
184 199
185 // Read ExHeader... 200 // Read ExHeader...
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index d9d68f154..9ae2de99f 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -13,7 +13,7 @@
13 13
14struct NCCH_Header { 14struct NCCH_Header {
15 u8 signature[0x100]; 15 u8 signature[0x100];
16 char magic[4]; 16 u32 magic;
17 u32 content_size; 17 u32 content_size;
18 u8 partition_id[8]; 18 u8 partition_id[8];
19 u16 maker_code; 19 u16 maker_code;
@@ -149,6 +149,13 @@ public:
149 AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { } 149 AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
150 150
151 /** 151 /**
152 * Returns the type of the file
153 * @param file FileUtil::IOFile open file
154 * @return FileType found, or FileType::Error if this loader doesn't know it
155 */
156 static FileType IdentifyType(FileUtil::IOFile& file);
157
158 /**
152 * Load the application 159 * Load the application
153 * @return ResultStatus result of function 160 * @return ResultStatus result of function
154 */ 161 */