summaryrefslogtreecommitdiff
path: root/src/core/loader/ncch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader/ncch.cpp')
-rw-r--r--src/core/loader/ncch.cpp172
1 files changed, 90 insertions, 82 deletions
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 60505bdfa..ba27eb75a 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -113,76 +113,80 @@ AppLoader_NCCH::AppLoader_NCCH(const std::string& filename) {
113 113
114/// AppLoader_NCCH destructor 114/// AppLoader_NCCH destructor
115AppLoader_NCCH::~AppLoader_NCCH() { 115AppLoader_NCCH::~AppLoader_NCCH() {
116 if (file.IsOpen())
117 file.Close();
118} 116}
119 117
120/** 118/**
121 * Loads .code section into memory for booting 119 * Loads .code section into memory for booting
122 * @return ResultStatus result of function 120 * @return ResultStatus result of function
123 */ 121 */
124ResultStatus AppLoader_NCCH::LoadExec() { 122ResultStatus AppLoader_NCCH::LoadExec() const {
125 if (!is_loaded) 123 if (!is_loaded)
126 return ResultStatus::ErrorNotLoaded; 124 return ResultStatus::ErrorNotLoaded;
127 125
128 ResultStatus res; 126 std::vector<u8> code;
129 code = ReadCode(res); 127 if (ResultStatus::Success == ReadCode(code)) {
130
131 if (ResultStatus::Success == res) {
132 Memory::WriteBlock(entry_point, &code[0], code.size()); 128 Memory::WriteBlock(entry_point, &code[0], code.size());
133 Kernel::LoadExec(entry_point); 129 Kernel::LoadExec(entry_point);
130 return ResultStatus::Success;
134 } 131 }
135 return res; 132 return ResultStatus::Error;
136} 133}
137 134
138/** 135/**
139 * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.) 136 * Reads an application ExeFS section of an NCCH file into AppLoader (e.g. .code, .logo, etc.)
140 * @param name Name of section to read out of NCCH file 137 * @param name Name of section to read out of NCCH file
141 * @param buffer Vector to read data into 138 * @param buffer Vector to read data into
142 * @param error ResultStatus result of function 139 * @return ResultStatus result of function
143 * @return Reference to buffer of data that was read
144 */ 140 */
145const std::vector<u8>& AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer, 141ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const {
146 ResultStatus& error) {
147 // Iterate through the ExeFs archive until we find the .code file... 142 // Iterate through the ExeFs archive until we find the .code file...
148 for (int i = 0; i < kMaxSections; i++) { 143 File::IOFile file(filename, "rb");
149 // Load the specified section... 144 if (file.IsOpen()) {
150 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) { 145 for (int i = 0; i < kMaxSections; i++) {
151 INFO_LOG(LOADER, "ExeFS section %d:", i); 146 // Load the specified section...
152 INFO_LOG(LOADER, " name: %s", exefs_header.section[i].name); 147 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
153 INFO_LOG(LOADER, " offset: 0x%08X", exefs_header.section[i].offset); 148 INFO_LOG(LOADER, "ExeFS section %d:", i);
154 INFO_LOG(LOADER, " size: 0x%08X", exefs_header.section[i].size); 149 INFO_LOG(LOADER, " name: %s", exefs_header.section[i].name);
155 150 INFO_LOG(LOADER, " offset: 0x%08X", exefs_header.section[i].offset);
156 s64 section_offset = (exefs_header.section[i].offset + exefs_offset + 151 INFO_LOG(LOADER, " size: 0x%08X", exefs_header.section[i].size);
157 sizeof(ExeFs_Header) + ncch_offset); 152
158 file.Seek(section_offset, 0); 153 s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
159 154 sizeof(ExeFs_Header)+ncch_offset);
160 // Section is compressed... 155 file.Seek(section_offset, 0);
161 if (i == 0 && is_compressed) { 156
162 // Read compressed .code section... 157 // Section is compressed...
163 std::unique_ptr<u8[]> temp_buffer(new u8[exefs_header.section[i].size]); 158 if (i == 0 && is_compressed) {
164 file.ReadBytes(&temp_buffer[0], exefs_header.section[i].size); 159 // Read compressed .code section...
165 160 std::unique_ptr<u8[]> temp_buffer;
166 // Decompress .code section... 161 try {
167 u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0], 162 temp_buffer.reset(new u8[exefs_header.section[i].size]);
168 exefs_header.section[i].size); 163 } catch (std::bad_alloc&) {
169 buffer.resize(decompressed_size); 164 return ResultStatus::ErrorMemoryAllocationFailed;
170 if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0], 165 }
171 decompressed_size)) { 166 file.ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
172 error = ResultStatus::ErrorInvalidFormat; 167
173 return buffer; 168 // Decompress .code section...
169 u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
170 exefs_header.section[i].size);
171 buffer.resize(decompressed_size);
172 if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
173 decompressed_size)) {
174 return ResultStatus::ErrorInvalidFormat;
175 }
176 // Section is uncompressed...
174 } 177 }
175 // Section is uncompressed... 178 else {
176 } else { 179 buffer.resize(exefs_header.section[i].size);
177 buffer.resize(exefs_header.section[i].size); 180 file.ReadBytes(&buffer[0], exefs_header.section[i].size);
178 file.ReadBytes(&buffer[0], exefs_header.section[i].size); 181 }
182 return ResultStatus::Success;
179 } 183 }
180 error = ResultStatus::Success;
181 return buffer;
182 } 184 }
185 } else {
186 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str());
187 return ResultStatus::Error;
183 } 188 }
184 error = ResultStatus::ErrorNotUsed; 189 return ResultStatus::ErrorNotUsed;
185 return buffer;
186} 190}
187 191
188/** 192/**
@@ -197,8 +201,7 @@ ResultStatus AppLoader_NCCH::Load() {
197 if (is_loaded) 201 if (is_loaded)
198 return ResultStatus::ErrorAlreadyLoaded; 202 return ResultStatus::ErrorAlreadyLoaded;
199 203
200 file = File::IOFile(filename, "rb"); 204 File::IOFile file(filename, "rb");
201
202 if (file.IsOpen()) { 205 if (file.IsOpen()) {
203 file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); 206 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
204 207
@@ -241,72 +244,77 @@ ResultStatus AppLoader_NCCH::Load() {
241 LoadExec(); // Load the executable into memory for booting 244 LoadExec(); // Load the executable into memory for booting
242 245
243 return ResultStatus::Success; 246 return ResultStatus::Success;
247 } else {
248 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str());
244 } 249 }
245 return ResultStatus::Error; 250 return ResultStatus::Error;
246} 251}
247 252
248/** 253/**
249 * Get the code (typically .code section) of the application 254 * Get the code (typically .code section) of the application
250 * @param error ResultStatus result of function 255 * @param buffer Reference to buffer to store data
251 * @return Reference to code buffer 256 * @return ResultStatus result of function
252 */ 257 */
253const std::vector<u8>& AppLoader_NCCH::ReadCode(ResultStatus& error) { 258ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const {
254 return LoadSectionExeFS(".code", code, error); 259 return LoadSectionExeFS(".code", buffer);
255} 260}
256 261
257/** 262/**
258 * Get the icon (typically icon section) of the application 263 * Get the icon (typically icon section) of the application
259 * @param error ResultStatus result of function 264 * @param buffer Reference to buffer to store data
260 * @return Reference to icon buffer 265 * @return ResultStatus result of function
261 */ 266 */
262const std::vector<u8>& AppLoader_NCCH::ReadIcon(ResultStatus& error) { 267ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) const {
263 return LoadSectionExeFS("icon", icon, error); 268 return LoadSectionExeFS("icon", buffer);
264} 269}
265 270
266/** 271/**
267 * Get the banner (typically banner section) of the application 272 * Get the banner (typically banner section) of the application
268 * @param error ResultStatus result of function 273 * @param buffer Reference to buffer to store data
269 * @return Reference to banner buffer 274 * @return ResultStatus result of function
270 */ 275 */
271const std::vector<u8>& AppLoader_NCCH::ReadBanner(ResultStatus& error) { 276ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) const {
272 return LoadSectionExeFS("banner", banner, error); 277 return LoadSectionExeFS("banner", buffer);
273} 278}
274 279
275/** 280/**
276 * Get the logo (typically logo section) of the application 281 * Get the logo (typically logo section) of the application
277 * @param error ResultStatus result of function 282 * @param buffer Reference to buffer to store data
278 * @return Reference to logo buffer 283 * @return ResultStatus result of function
279 */ 284 */
280const std::vector<u8>& AppLoader_NCCH::ReadLogo(ResultStatus& error) { 285ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const {
281 return LoadSectionExeFS("logo", logo, error); 286 return LoadSectionExeFS("logo", buffer);
282} 287}
283 288
284/** 289/**
285 * Get the RomFs archive of the application 290 * Get the RomFS of the application
286 * @param error ResultStatus result of function 291 * @param buffer Reference to buffer to store data
287 * @return Reference to RomFs archive buffer 292 * @return ResultStatus result of function
288 */ 293 */
289const std::vector<u8>& AppLoader_NCCH::ReadRomFS(ResultStatus& error) { 294ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
290 // Check if the NCCH has a RomFS... 295 File::IOFile file(filename, "rb");
291 if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) { 296 if (file.IsOpen()) {
292 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000; 297 // Check if the NCCH has a RomFS...
293 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000; 298 if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
299 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
300 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
294 301
295 INFO_LOG(LOADER, "RomFS offset: 0x%08X", romfs_offset); 302 INFO_LOG(LOADER, "RomFS offset: 0x%08X", romfs_offset);
296 INFO_LOG(LOADER, "RomFS size: 0x%08X", romfs_size); 303 INFO_LOG(LOADER, "RomFS size: 0x%08X", romfs_size);
297 304
298 romfs.resize(romfs_size); 305 buffer.resize(romfs_size);
299 306
300 file.Seek(romfs_offset, 0); 307 file.Seek(romfs_offset, 0);
301 file.ReadBytes(&romfs[0], romfs_size); 308 file.ReadBytes(&buffer[0], romfs_size);
302 309
303 error = ResultStatus::Success; 310 return ResultStatus::Success;
304 return romfs; 311 }
305 } else {
306 NOTICE_LOG(LOADER, "RomFS unused"); 312 NOTICE_LOG(LOADER, "RomFS unused");
313 return ResultStatus::ErrorNotUsed;
314 } else {
315 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str());
307 } 316 }
308 error = ResultStatus::ErrorNotUsed; 317 return ResultStatus::Error;
309 return romfs;
310} 318}
311 319
312} // namespace Loader 320} // namespace Loader