diff options
| author | 2015-01-06 23:10:13 +0000 | |
|---|---|---|
| committer | 2015-01-15 22:23:08 +0100 | |
| commit | 82ec17db7df53ed1c376d1cdaa9a6587719a546d (patch) | |
| tree | 3c2236849146037fbba2fb75ea8a50f53b847a17 /src/core/loader | |
| parent | Loader: Don’t assume the file hasn’t been read before. (diff) | |
| download | yuzu-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.cpp | 13 | ||||
| -rw-r--r-- | src/core/loader/3dsx.h | 7 | ||||
| -rw-r--r-- | src/core/loader/elf.cpp | 12 | ||||
| -rw-r--r-- | src/core/loader/elf.h | 7 | ||||
| -rw-r--r-- | src/core/loader/loader.cpp | 60 | ||||
| -rw-r--r-- | src/core/loader/loader.h | 11 | ||||
| -rw-r--r-- | src/core/loader/ncch.cpp | 19 | ||||
| -rw-r--r-- | src/core/loader/ncch.h | 9 |
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 { | |||
| 44 | static const u32 RELOCBUFSIZE = 512; | 44 | static const u32 RELOCBUFSIZE = 512; |
| 45 | 45 | ||
| 46 | // File header | 46 | // File header |
| 47 | static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX' | ||
| 48 | #pragma pack(1) | 47 | #pragma pack(1) |
| 49 | struct THREEDSX_Header | 48 | struct 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 | ||
| 204 | FileType 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 | |||
| 205 | ResultStatus AppLoader_THREEDSX::Load() { | 216 | ResultStatus 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 | ||
| 331 | namespace Loader { | 331 | namespace Loader { |
| 332 | 332 | ||
| 333 | FileType 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 | |||
| 333 | ResultStatus AppLoader_ELF::Load() { | 345 | ResultStatus 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 | */ | ||
| 25 | static 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 | */ |
| 26 | FileType IdentifyFile(const std::string &filename) { | 47 | static 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 | ||
| 41 | static 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 |
| 42 | class AppLoader : NonCopyable { | 46 | class AppLoader : NonCopyable { |
| 43 | public: | 47 | public: |
| @@ -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 | */ | ||
| 108 | FileType 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 | ||
| 100 | FileType 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 | |||
| 100 | ResultStatus AppLoader_NCCH::LoadExec() const { | 115 | ResultStatus 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 | ||
| 14 | struct NCCH_Header { | 14 | struct 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 | */ |