diff options
| author | 2015-01-06 21:30:40 +0000 | |
|---|---|---|
| committer | 2015-01-15 21:21:26 +0000 | |
| commit | b5237e885df72f6c37532fc8af9573966e7b07e5 (patch) | |
| tree | fdfd4da299cc2779f35fcc30e770b85b9e710166 /src/core/loader/ncch.cpp | |
| parent | Loader: Initialize the default NCCH values in the class declaration, not in t... (diff) | |
| download | yuzu-b5237e885df72f6c37532fc8af9573966e7b07e5.tar.gz yuzu-b5237e885df72f6c37532fc8af9573966e7b07e5.tar.xz yuzu-b5237e885df72f6c37532fc8af9573966e7b07e5.zip | |
Loader: Keep a reference to the file and pass it to the correct AppLoader, instead of loading it multiple times.
Diffstat (limited to 'src/core/loader/ncch.cpp')
| -rw-r--r-- | src/core/loader/ncch.cpp | 190 |
1 files changed, 84 insertions, 106 deletions
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 | ||
| 103 | AppLoader_NCCH::AppLoader_NCCH(const std::string& filename) { | ||
| 104 | this->filename = filename; | ||
| 105 | } | ||
| 106 | |||
| 107 | /// AppLoader_NCCH destructor | ||
| 108 | AppLoader_NCCH::~AppLoader_NCCH() { | ||
| 109 | } | ||
| 110 | |||
| 111 | ResultStatus AppLoader_NCCH::LoadExec() const { | 100 | ResultStatus 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 | ||
| 124 | ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { | 113 | ResultStatus 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 | ||
| 175 | ResultStatus AppLoader_NCCH::Load() { | 161 | ResultStatus 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 | ||
| 230 | ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const { | 211 | ResultStatus 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 | ||
| 246 | ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { | 227 | ResultStatus 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 | ||
| 272 | u64 AppLoader_NCCH::GetProgramId() const { | 250 | u64 AppLoader_NCCH::GetProgramId() const { |