1 // Copyright 2014 Citra Emulator Project
2 // Licensed under GPLv2 or any later version
3 // Refer to the license.txt file included.
4
5 #include <memory>
6 #include <string>
7 #include "common/logging/log.h"
8 #include "common/string_util.h"
9 #include "core/hle/kernel/process.h"
10 #include "core/loader/3dsx.h"
11 #include "core/loader/elf.h"
12 #include "core/loader/ncch.h"
13
14 ////////////////////////////////////////////////////////////////////////////////////////////////////
15
16 namespace Loader {
17
IdentifyFile(FileUtil::IOFile & file)18 FileType IdentifyFile(FileUtil::IOFile& file) {
19 FileType type;
20
21 #define CHECK_TYPE(loader) \
22 type = AppLoader_##loader::IdentifyType(file); \
23 if (FileType::Error != type) \
24 return type;
25
26 CHECK_TYPE(THREEDSX)
27 CHECK_TYPE(ELF)
28 CHECK_TYPE(NCCH)
29
30 #undef CHECK_TYPE
31
32 return FileType::Unknown;
33 }
34
IdentifyFile(const std::string & file_name)35 FileType IdentifyFile(const std::string& file_name) {
36 FileUtil::IOFile file(file_name, "rb");
37 if (!file.IsOpen()) {
38 LOG_ERROR(Loader, "Failed to load file {}", file_name);
39 return FileType::Unknown;
40 }
41
42 return IdentifyFile(file);
43 }
44
GuessFromExtension(const std::string & extension_)45 FileType GuessFromExtension(const std::string& extension_) {
46 std::string extension = Common::ToLower(extension_);
47
48 if (extension == ".elf" || extension == ".axf")
49 return FileType::ELF;
50
51 if (extension == ".cci" || extension == ".3ds")
52 return FileType::CCI;
53
54 if (extension == ".cxi" || extension == ".app")
55 return FileType::CXI;
56
57 if (extension == ".3dsx")
58 return FileType::THREEDSX;
59
60 if (extension == ".cia")
61 return FileType::CIA;
62
63 return FileType::Unknown;
64 }
65
GetFileTypeString(FileType type)66 const char* GetFileTypeString(FileType type) {
67 switch (type) {
68 case FileType::CCI:
69 return "NCSD";
70 case FileType::CXI:
71 return "NCCH";
72 case FileType::CIA:
73 return "CIA";
74 case FileType::ELF:
75 return "ELF";
76 case FileType::THREEDSX:
77 return "3DSX";
78 case FileType::Error:
79 case FileType::Unknown:
80 break;
81 }
82
83 return "unknown";
84 }
85
86 /**
87 * Get a loader for a file with a specific type
88 * @param file The file to load
89 * @param type The type of the file
90 * @param filename the file name (without path)
91 * @param filepath the file full path (with name)
92 * @return std::unique_ptr<AppLoader> a pointer to a loader object; nullptr for unsupported type
93 */
GetFileLoader(FileUtil::IOFile && file,FileType type,const std::string & filename,const std::string & filepath)94 static std::unique_ptr<AppLoader> GetFileLoader(FileUtil::IOFile&& file, FileType type,
95 const std::string& filename,
96 const std::string& filepath) {
97 switch (type) {
98
99 // 3DSX file format.
100 case FileType::THREEDSX:
101 return std::make_unique<AppLoader_THREEDSX>(std::move(file), filename, filepath);
102
103 // Standard ELF file format.
104 case FileType::ELF:
105 return std::make_unique<AppLoader_ELF>(std::move(file), filename);
106
107 // NCCH/NCSD container formats.
108 case FileType::CXI:
109 case FileType::CCI:
110 return std::make_unique<AppLoader_NCCH>(std::move(file), filepath);
111
112 default:
113 return nullptr;
114 }
115 }
116
GetLoader(const std::string & filename)117 std::unique_ptr<AppLoader> GetLoader(const std::string& filename) {
118 FileUtil::IOFile file(filename, "rb");
119 if (!file.IsOpen()) {
120 LOG_ERROR(Loader, "Failed to load file {}", filename);
121 return nullptr;
122 }
123
124 std::string filename_filename, filename_extension;
125 Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension);
126
127 FileType type = IdentifyFile(file);
128 FileType filename_type = GuessFromExtension(filename_extension);
129
130 if (type != filename_type) {
131 LOG_WARNING(Loader, "File {} has a different type than its extension.", filename);
132 if (FileType::Unknown == type)
133 type = filename_type;
134 }
135
136 LOG_DEBUG(Loader, "Loading file {} as {}...", filename, GetFileTypeString(type));
137
138 return GetFileLoader(std::move(file), type, filename_filename, filename);
139 }
140
141 } // namespace Loader
142