summaryrefslogtreecommitdiff
path: root/src/core/loader
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/3dsx.cpp21
-rw-r--r--src/core/loader/3dsx.h7
-rw-r--r--src/core/loader/elf.cpp30
-rw-r--r--src/core/loader/elf.h7
-rw-r--r--src/core/loader/loader.cpp23
-rw-r--r--src/core/loader/loader.h7
-rw-r--r--src/core/loader/ncch.cpp190
-rw-r--r--src/core/loader/ncch.h7
8 files changed, 116 insertions, 176 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 54ee992fc..873ee8b25 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -199,28 +199,15 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
199 return ERROR_NONE; 199 return ERROR_NONE;
200} 200}
201 201
202/// AppLoader_DSX constructor
203AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) {
204}
205
206/// AppLoader_DSX destructor
207AppLoader_THREEDSX::~AppLoader_THREEDSX() {
208}
209
210ResultStatus AppLoader_THREEDSX::Load() { 202ResultStatus AppLoader_THREEDSX::Load() {
211 LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str());
212
213 if (is_loaded) 203 if (is_loaded)
214 return ResultStatus::ErrorAlreadyLoaded; 204 return ResultStatus::ErrorAlreadyLoaded;
215 205
216 FileUtil::IOFile file(filename, "rb"); 206 if (!file->IsOpen())
217
218 if (file.IsOpen()) {
219 Load3DSXFile(file, 0x00100000);
220 Kernel::LoadExec(0x00100000);
221 } else {
222 return ResultStatus::Error; 207 return ResultStatus::Error;
223 } 208
209 Load3DSXFile(*file, 0x00100000);
210 Kernel::LoadExec(0x00100000);
224 211
225 is_loaded = true; 212 is_loaded = true;
226 return ResultStatus::Success; 213 return ResultStatus::Success;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index f28224628..2f2e8bec0 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -15,18 +15,13 @@ namespace Loader {
15/// Loads an 3DSX file 15/// Loads an 3DSX file
16class AppLoader_THREEDSX final : public AppLoader { 16class AppLoader_THREEDSX final : public AppLoader {
17public: 17public:
18 AppLoader_THREEDSX(const std::string& filename); 18 AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
19 ~AppLoader_THREEDSX() override;
20 19
21 /** 20 /**
22 * Load the bootable file 21 * Load the bootable file
23 * @return ResultStatus result of function 22 * @return ResultStatus result of function
24 */ 23 */
25 ResultStatus Load() override; 24 ResultStatus Load() override;
26
27private:
28 std::string filename;
29 bool is_loaded = false;
30}; 25};
31 26
32} // namespace Loader 27} // namespace Loader
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index ee711d8b2..d1a1ef595 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -330,34 +330,20 @@ bool ElfReader::LoadSymbols() {
330 330
331namespace Loader { 331namespace Loader {
332 332
333/// AppLoader_ELF constructor
334AppLoader_ELF::AppLoader_ELF(const std::string& filename) {
335 this->filename = filename;
336}
337
338/// AppLoader_NCCH destructor
339AppLoader_ELF::~AppLoader_ELF() {
340}
341
342ResultStatus AppLoader_ELF::Load() { 333ResultStatus AppLoader_ELF::Load() {
343 LOG_INFO(Loader, "Loading ELF file %s...", filename.c_str());
344
345 if (is_loaded) 334 if (is_loaded)
346 return ResultStatus::ErrorAlreadyLoaded; 335 return ResultStatus::ErrorAlreadyLoaded;
347 336
348 FileUtil::IOFile file(filename, "rb"); 337 if (!file->IsOpen())
338 return ResultStatus::Error;
349 339
350 if (file.IsOpen()) { 340 u32 size = static_cast<u32>(file->GetSize());
351 u32 size = (u32)file.GetSize(); 341 std::unique_ptr<u8[]> buffer(new u8[size]);
352 std::unique_ptr<u8[]> buffer(new u8[size]); 342 file->ReadBytes(&buffer[0], size);
353 file.ReadBytes(&buffer[0], size);
354 343
355 ElfReader elf_reader(&buffer[0]); 344 ElfReader elf_reader(&buffer[0]);
356 elf_reader.LoadInto(0x00100000); 345 elf_reader.LoadInto(0x00100000);
357 Kernel::LoadExec(elf_reader.GetEntryPoint()); 346 Kernel::LoadExec(elf_reader.GetEntryPoint());
358 } else {
359 return ResultStatus::Error;
360 }
361 347
362 is_loaded = true; 348 is_loaded = true;
363 return ResultStatus::Success; 349 return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 856722f1e..1c476c86b 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -15,18 +15,13 @@ namespace Loader {
15/// Loads an ELF/AXF file 15/// Loads an ELF/AXF file
16class AppLoader_ELF final : public AppLoader { 16class AppLoader_ELF final : public AppLoader {
17public: 17public:
18 AppLoader_ELF(const std::string& filename); 18 AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
19 ~AppLoader_ELF() override;
20 19
21 /** 20 /**
22 * Load the bootable file 21 * Load the bootable file
23 * @return ResultStatus result of function 22 * @return ResultStatus result of function
24 */ 23 */
25 ResultStatus Load() override; 24 ResultStatus Load() override;
26
27private:
28 std::string filename;
29 bool is_loaded = false;
30}; 25};
31 26
32} // namespace Loader 27} // namespace Loader
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 32196a1dc..fd32b7b20 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -56,20 +56,24 @@ FileType IdentifyFile(const std::string &filename) {
56ResultStatus LoadFile(const std::string& filename) { 56ResultStatus LoadFile(const std::string& filename) {
57 LOG_INFO(Loader, "Loading file %s...", filename.c_str()); 57 LOG_INFO(Loader, "Loading file %s...", filename.c_str());
58 58
59 std::unique_ptr<FileUtil::IOFile> file(new FileUtil::IOFile(filename, "rb"));
60 if (!file->IsOpen())
61 return ResultStatus::Error;
62
59 switch (IdentifyFile(filename)) { 63 switch (IdentifyFile(filename)) {
60 64
61 //3DSX file format... 65 //3DSX file format...
62 case FileType::THREEDSX: 66 case FileType::THREEDSX:
63 return AppLoader_THREEDSX(filename).Load(); 67 return AppLoader_THREEDSX(std::move(file)).Load();
64 68
65 // Standard ELF file format... 69 // Standard ELF file format...
66 case FileType::ELF: 70 case FileType::ELF:
67 return AppLoader_ELF(filename).Load(); 71 return AppLoader_ELF(std::move(file)).Load();
68 72
69 // NCCH/NCSD container formats... 73 // NCCH/NCSD container formats...
70 case FileType::CXI: 74 case FileType::CXI:
71 case FileType::CCI: { 75 case FileType::CCI: {
72 AppLoader_NCCH app_loader(filename); 76 AppLoader_NCCH app_loader(std::move(file));
73 77
74 // Load application and RomFS 78 // Load application and RomFS
75 if (ResultStatus::Success == app_loader.Load()) { 79 if (ResultStatus::Success == app_loader.Load()) {
@@ -83,16 +87,11 @@ ResultStatus LoadFile(const std::string& filename) {
83 // Raw BIN file format... 87 // Raw BIN file format...
84 case FileType::BIN: 88 case FileType::BIN:
85 { 89 {
86 LOG_INFO(Loader, "Loading BIN file %s...", filename.c_str()); 90 size_t size = (size_t)file->GetSize();
87 91 if (file->ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), size) != size)
88 FileUtil::IOFile file(filename, "rb");
89
90 if (file.IsOpen()) {
91 file.ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), (size_t)file.GetSize());
92 Kernel::LoadExec(Memory::EXEFS_CODE_VADDR);
93 } else {
94 return ResultStatus::Error; 92 return ResultStatus::Error;
95 } 93
94 Kernel::LoadExec(Memory::EXEFS_CODE_VADDR);
96 return ResultStatus::Success; 95 return ResultStatus::Success;
97 } 96 }
98 97
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index ec5534d41..b4fc8636d 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -7,6 +7,7 @@
7#include <vector> 7#include <vector>
8 8
9#include "common/common.h" 9#include "common/common.h"
10#include "common/file_util.h"
10 11
11//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
12// Loader namespace 13// Loader namespace
@@ -40,7 +41,7 @@ enum class ResultStatus {
40/// Interface for loading an application 41/// Interface for loading an application
41class AppLoader : NonCopyable { 42class AppLoader : NonCopyable {
42public: 43public:
43 AppLoader() { } 44 AppLoader(std::unique_ptr<FileUtil::IOFile>&& file) : file(std::move(file)) { }
44 virtual ~AppLoader() { } 45 virtual ~AppLoader() { }
45 46
46 /** 47 /**
@@ -93,6 +94,10 @@ public:
93 virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const { 94 virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const {
94 return ResultStatus::ErrorNotImplemented; 95 return ResultStatus::ErrorNotImplemented;
95 } 96 }
97
98protected:
99 std::unique_ptr<FileUtil::IOFile> file;
100 bool is_loaded = false;
96}; 101};
97 102
98/** 103/**
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 883a0f753..eca57d14b 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -4,8 +4,6 @@
4 4
5#include <memory> 5#include <memory>
6 6
7#include "common/file_util.h"
8
9#include "core/loader/ncch.h" 7#include "core/loader/ncch.h"
10#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
11#include "core/mem_map.h" 9#include "core/mem_map.h"
@@ -99,15 +97,6 @@ static bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompresse
99//////////////////////////////////////////////////////////////////////////////////////////////////// 97////////////////////////////////////////////////////////////////////////////////////////////////////
100// AppLoader_NCCH class 98// AppLoader_NCCH class
101 99
102/// AppLoader_NCCH constructor
103AppLoader_NCCH::AppLoader_NCCH(const std::string& filename) {
104 this->filename = filename;
105}
106
107/// AppLoader_NCCH destructor
108AppLoader_NCCH::~AppLoader_NCCH() {
109}
110
111ResultStatus AppLoader_NCCH::LoadExec() const { 100ResultStatus AppLoader_NCCH::LoadExec() const {
112 if (!is_loaded) 101 if (!is_loaded)
113 return ResultStatus::ErrorNotLoaded; 102 return ResultStatus::ErrorNotLoaded;
@@ -123,108 +112,100 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
123 112
124ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { 113ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const {
125 // Iterate through the ExeFs archive until we find the .code file... 114 // Iterate through the ExeFs archive until we find the .code file...
126 FileUtil::IOFile file(filename, "rb"); 115 if (!file->IsOpen())
127 if (file.IsOpen()) { 116 return ResultStatus::Error;
128 LOG_DEBUG(Loader, "%d sections:", kMaxSections); 117
129 for (int i = 0; i < kMaxSections; i++) { 118 LOG_DEBUG(Loader, "%d sections:", kMaxSections);
130 // Load the specified section... 119 for (int i = 0; i < kMaxSections; i++) {
131 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) { 120 // Load the specified section...
132 LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", i, 121 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
133 exefs_header.section[i].offset, exefs_header.section[i].size, 122 LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", i,
134 exefs_header.section[i].name); 123 exefs_header.section[i].offset, exefs_header.section[i].size,
135 124 exefs_header.section[i].name);
136 s64 section_offset = (exefs_header.section[i].offset + exefs_offset + 125
137 sizeof(ExeFs_Header)+ncch_offset); 126 s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
138 file.Seek(section_offset, 0); 127 sizeof(ExeFs_Header)+ncch_offset);
139 128 file->Seek(section_offset, 0);
140 // Section is compressed... 129
141 if (i == 0 && is_compressed) { 130 // Section is compressed...
142 // Read compressed .code section... 131 if (i == 0 && is_compressed) {
143 std::unique_ptr<u8[]> temp_buffer; 132 // Read compressed .code section...
144 try { 133 std::unique_ptr<u8[]> temp_buffer;
145 temp_buffer.reset(new u8[exefs_header.section[i].size]); 134 try {
146 } catch (std::bad_alloc&) { 135 temp_buffer.reset(new u8[exefs_header.section[i].size]);
147 return ResultStatus::ErrorMemoryAllocationFailed; 136 } catch (std::bad_alloc&) {
148 } 137 return ResultStatus::ErrorMemoryAllocationFailed;
149 file.ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
150
151 // Decompress .code section...
152 u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
153 exefs_header.section[i].size);
154 buffer.resize(decompressed_size);
155 if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
156 decompressed_size)) {
157 return ResultStatus::ErrorInvalidFormat;
158 }
159 // Section is uncompressed...
160 } 138 }
161 else { 139 file->ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
162 buffer.resize(exefs_header.section[i].size); 140
163 file.ReadBytes(&buffer[0], exefs_header.section[i].size); 141 // Decompress .code section...
142 u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
143 exefs_header.section[i].size);
144 buffer.resize(decompressed_size);
145 if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
146 decompressed_size)) {
147 return ResultStatus::ErrorInvalidFormat;
164 } 148 }
165 return ResultStatus::Success; 149 // Section is uncompressed...
166 } 150 }
151 else {
152 buffer.resize(exefs_header.section[i].size);
153 file->ReadBytes(&buffer[0], exefs_header.section[i].size);
154 }
155 return ResultStatus::Success;
167 } 156 }
168 } else {
169 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
170 return ResultStatus::Error;
171 } 157 }
172 return ResultStatus::ErrorNotUsed; 158 return ResultStatus::ErrorNotUsed;
173} 159}
174 160
175ResultStatus AppLoader_NCCH::Load() { 161ResultStatus AppLoader_NCCH::Load() {
176 LOG_INFO(Loader, "Loading NCCH file %s...", filename.c_str());
177
178 if (is_loaded) 162 if (is_loaded)
179 return ResultStatus::ErrorAlreadyLoaded; 163 return ResultStatus::ErrorAlreadyLoaded;
180 164
181 FileUtil::IOFile file(filename, "rb"); 165 if (!file->IsOpen())
182 if (file.IsOpen()) { 166 return ResultStatus::Error;
183 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
184 167
185 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... 168 file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
186 if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
187 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
188 ncch_offset = 0x4000;
189 file.Seek(ncch_offset, 0);
190 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
191 }
192 169
193 // Verify we are loading the correct file type... 170 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
194 if (0 != memcmp(&ncch_header.magic, "NCCH", 4)) 171 if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
195 return ResultStatus::ErrorInvalidFormat; 172 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
173 ncch_offset = 0x4000;
174 file->Seek(ncch_offset, 0);
175 file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
176 }
196 177
197 // Read ExHeader... 178 // Verify we are loading the correct file type...
179 if (0 != memcmp(&ncch_header.magic, "NCCH", 4))
180 return ResultStatus::ErrorInvalidFormat;
198 181
199 file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)); 182 // Read ExHeader...
200 183
201 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; 184 file->ReadBytes(&exheader_header, sizeof(ExHeader_Header));
202 entry_point = exheader_header.codeset_info.text.address;
203 185
204 LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name); 186 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
205 LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no"); 187 entry_point = exheader_header.codeset_info.text.address;
206 LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
207 188
208 // Read ExeFS... 189 LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name);
190 LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
191 LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
209 192
210 exefs_offset = ncch_header.exefs_offset * kBlockSize; 193 // Read ExeFS...
211 u32 exefs_size = ncch_header.exefs_size * kBlockSize;
212 194
213 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset); 195 exefs_offset = ncch_header.exefs_offset * kBlockSize;
214 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size); 196 u32 exefs_size = ncch_header.exefs_size * kBlockSize;
215 197
216 file.Seek(exefs_offset + ncch_offset, 0); 198 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
217 file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)); 199 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
218 200
219 LoadExec(); // Load the executable into memory for booting 201 file->Seek(exefs_offset + ncch_offset, 0);
202 file->ReadBytes(&exefs_header, sizeof(ExeFs_Header));
220 203
221 is_loaded = true; // Set state to loaded 204 LoadExec(); // Load the executable into memory for booting
222 205
223 return ResultStatus::Success; 206 is_loaded = true; // Set state to loaded
224 } else { 207
225 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str()); 208 return ResultStatus::Success;
226 }
227 return ResultStatus::Error;
228} 209}
229 210
230ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const { 211ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const {
@@ -244,29 +225,26 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const {
244} 225}
245 226
246ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { 227ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
247 FileUtil::IOFile file(filename, "rb"); 228 if (!file->IsOpen())
248 if (file.IsOpen()) { 229 return ResultStatus::Error;
249 // Check if the NCCH has a RomFS...
250 if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
251 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
252 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
253 230
254 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); 231 // Check if the NCCH has a RomFS...
255 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); 232 if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
233 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
234 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
256 235
257 buffer.resize(romfs_size); 236 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
237 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
258 238
259 file.Seek(romfs_offset, 0); 239 buffer.resize(romfs_size);
260 file.ReadBytes(&buffer[0], romfs_size);
261 240
262 return ResultStatus::Success; 241 file->Seek(romfs_offset, 0);
263 } 242 file->ReadBytes(&buffer[0], romfs_size);
264 LOG_DEBUG(Loader, "NCCH has no RomFS"); 243
265 return ResultStatus::ErrorNotUsed; 244 return ResultStatus::Success;
266 } else {
267 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
268 } 245 }
269 return ResultStatus::Error; 246 LOG_DEBUG(Loader, "NCCH has no RomFS");
247 return ResultStatus::ErrorNotUsed;
270} 248}
271 249
272u64 AppLoader_NCCH::GetProgramId() const { 250u64 AppLoader_NCCH::GetProgramId() const {
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 578513f77..d9d68f154 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -5,7 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include "common/common.h" 7#include "common/common.h"
8#include "common/file_util.h"
9 8
10#include "core/loader/loader.h" 9#include "core/loader/loader.h"
11 10
@@ -147,8 +146,7 @@ namespace Loader {
147/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) 146/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
148class AppLoader_NCCH final : public AppLoader { 147class AppLoader_NCCH final : public AppLoader {
149public: 148public:
150 AppLoader_NCCH(const std::string& filename); 149 AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
151 ~AppLoader_NCCH() override;
152 150
153 /** 151 /**
154 * Load the application 152 * Load the application
@@ -213,9 +211,6 @@ private:
213 */ 211 */
214 ResultStatus LoadExec() const; 212 ResultStatus LoadExec() const;
215 213
216 std::string filename;
217
218 bool is_loaded = false;
219 bool is_compressed = false; 214 bool is_compressed = false;
220 215
221 u32 entry_point = 0; 216 u32 entry_point = 0;