From b5237e885df72f6c37532fc8af9573966e7b07e5 Mon Sep 17 00:00:00 2001
From: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
Date: Tue, 6 Jan 2015 21:30:40 +0000
Subject: [PATCH] Loader: Keep a reference to the file and pass it to the
 correct AppLoader, instead of loading it multiple times.

---
 src/core/loader/3dsx.cpp   |  21 +---
 src/core/loader/3dsx.h     |   7 +-
 src/core/loader/elf.cpp    |  30 ++----
 src/core/loader/elf.h      |   7 +-
 src/core/loader/loader.cpp |  23 +++--
 src/core/loader/loader.h   |   7 +-
 src/core/loader/ncch.cpp   | 190 ++++++++++++++++---------------------
 src/core/loader/ncch.h     |   7 +-
 8 files changed, 116 insertions(+), 176 deletions(-)

diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 54ee992fce..873ee8b251 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)
     return ERROR_NONE;
 }
 
-/// AppLoader_DSX constructor
-AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) {
-}
-
-/// AppLoader_DSX destructor
-AppLoader_THREEDSX::~AppLoader_THREEDSX() {
-}
-
 ResultStatus AppLoader_THREEDSX::Load() {
-    LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str());
-
     if (is_loaded)
         return ResultStatus::ErrorAlreadyLoaded;
 
-    FileUtil::IOFile file(filename, "rb");
-
-    if (file.IsOpen()) {
-        Load3DSXFile(file, 0x00100000);
-        Kernel::LoadExec(0x00100000);
-    } else {
+    if (!file->IsOpen())
         return ResultStatus::Error;
-    }
+
+    Load3DSXFile(*file, 0x00100000);
+    Kernel::LoadExec(0x00100000);
 
     is_loaded = true;
     return ResultStatus::Success;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index f282246284..2f2e8bec01 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -15,18 +15,13 @@ namespace Loader {
 /// Loads an 3DSX file
 class AppLoader_THREEDSX final : public AppLoader {
 public:
-    AppLoader_THREEDSX(const std::string& filename);
-    ~AppLoader_THREEDSX() override;
+    AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
 
     /**
      * Load the bootable file
      * @return ResultStatus result of function
      */
     ResultStatus Load() override;
-
-private:
-    std::string filename;
-    bool        is_loaded = false;
 };
 
 } // namespace Loader
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index ee711d8b2d..d1a1ef5952 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -330,34 +330,20 @@ bool ElfReader::LoadSymbols() {
 
 namespace Loader {
 
-/// AppLoader_ELF constructor
-AppLoader_ELF::AppLoader_ELF(const std::string& filename) {
-    this->filename = filename;
-}
-
-/// AppLoader_NCCH destructor
-AppLoader_ELF::~AppLoader_ELF() {
-}
-
 ResultStatus AppLoader_ELF::Load() {
-    LOG_INFO(Loader, "Loading ELF file %s...", filename.c_str());
-
     if (is_loaded)
         return ResultStatus::ErrorAlreadyLoaded;
 
-    FileUtil::IOFile file(filename, "rb");
+    if (!file->IsOpen())
+        return ResultStatus::Error;
 
-    if (file.IsOpen()) {
-        u32 size = (u32)file.GetSize();
-        std::unique_ptr<u8[]> buffer(new u8[size]);
-        file.ReadBytes(&buffer[0], size);
+    u32 size = static_cast<u32>(file->GetSize());
+    std::unique_ptr<u8[]> buffer(new u8[size]);
+    file->ReadBytes(&buffer[0], size);
 
-        ElfReader elf_reader(&buffer[0]);
-        elf_reader.LoadInto(0x00100000);
-        Kernel::LoadExec(elf_reader.GetEntryPoint());
-    } else {
-        return ResultStatus::Error;
-    }
+    ElfReader elf_reader(&buffer[0]);
+    elf_reader.LoadInto(0x00100000);
+    Kernel::LoadExec(elf_reader.GetEntryPoint());
 
     is_loaded = true;
     return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 856722f1e0..1c476c86b9 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -15,18 +15,13 @@ namespace Loader {
 /// Loads an ELF/AXF file
 class AppLoader_ELF final : public AppLoader {
 public:
-    AppLoader_ELF(const std::string& filename);
-    ~AppLoader_ELF() override;
+    AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
 
     /**
      * Load the bootable file
      * @return ResultStatus result of function
      */
     ResultStatus Load() override;
-
-private:
-    std::string filename;
-    bool        is_loaded = false;
 };
 
 } // namespace Loader
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 32196a1dc6..fd32b7b204 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -56,20 +56,24 @@ FileType IdentifyFile(const std::string &filename) {
 ResultStatus LoadFile(const std::string& filename) {
     LOG_INFO(Loader, "Loading file %s...", filename.c_str());
 
+    std::unique_ptr<FileUtil::IOFile> file(new FileUtil::IOFile(filename, "rb"));
+    if (!file->IsOpen())
+        return ResultStatus::Error;
+
     switch (IdentifyFile(filename)) {
 
     //3DSX file format...
     case FileType::THREEDSX:
-        return AppLoader_THREEDSX(filename).Load();
+        return AppLoader_THREEDSX(std::move(file)).Load();
 
     // Standard ELF file format...
     case FileType::ELF:
-        return AppLoader_ELF(filename).Load();
+        return AppLoader_ELF(std::move(file)).Load();
 
     // NCCH/NCSD container formats...
     case FileType::CXI:
     case FileType::CCI: {
-        AppLoader_NCCH app_loader(filename);
+        AppLoader_NCCH app_loader(std::move(file));
 
         // Load application and RomFS
         if (ResultStatus::Success == app_loader.Load()) {
@@ -83,16 +87,11 @@ ResultStatus LoadFile(const std::string& filename) {
     // Raw BIN file format...
     case FileType::BIN:
     {
-        LOG_INFO(Loader, "Loading BIN file %s...", filename.c_str());
-
-        FileUtil::IOFile file(filename, "rb");
-
-        if (file.IsOpen()) {
-            file.ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), (size_t)file.GetSize());
-            Kernel::LoadExec(Memory::EXEFS_CODE_VADDR);
-        } else {
+        size_t size = (size_t)file->GetSize();
+        if (file->ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), size) != size)
             return ResultStatus::Error;
-        }
+
+        Kernel::LoadExec(Memory::EXEFS_CODE_VADDR);
         return ResultStatus::Success;
     }
 
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index ec5534d419..b4fc8636dd 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -7,6 +7,7 @@
 #include <vector>
 
 #include "common/common.h"
+#include "common/file_util.h"
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Loader namespace
@@ -40,7 +41,7 @@ enum class ResultStatus {
 /// Interface for loading an application
 class AppLoader : NonCopyable {
 public:
-    AppLoader() { }
+    AppLoader(std::unique_ptr<FileUtil::IOFile>&& file) : file(std::move(file)) { }
     virtual ~AppLoader() { }
 
     /**
@@ -93,6 +94,10 @@ public:
     virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const {
         return ResultStatus::ErrorNotImplemented;
     }
+
+protected:
+    std::unique_ptr<FileUtil::IOFile> file;
+    bool                              is_loaded = false;
 };
 
 /**
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 883a0f7535..eca57d14b4 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -4,8 +4,6 @@
 
 #include <memory>
 
-#include "common/file_util.h"
-
 #include "core/loader/ncch.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/mem_map.h"
@@ -99,15 +97,6 @@ static bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompresse
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // AppLoader_NCCH class
 
-/// AppLoader_NCCH constructor
-AppLoader_NCCH::AppLoader_NCCH(const std::string& filename) {
-    this->filename = filename;
-}
-
-/// AppLoader_NCCH destructor
-AppLoader_NCCH::~AppLoader_NCCH() {
-}
-
 ResultStatus AppLoader_NCCH::LoadExec() const {
     if (!is_loaded)
         return ResultStatus::ErrorNotLoaded;
@@ -123,108 +112,100 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
 
 ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const {
     // Iterate through the ExeFs archive until we find the .code file...
-    FileUtil::IOFile file(filename, "rb");
-    if (file.IsOpen()) {
-        LOG_DEBUG(Loader, "%d sections:", kMaxSections);
-        for (int i = 0; i < kMaxSections; i++) {
-            // Load the specified section...
-            if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
-                LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", i,
-                        exefs_header.section[i].offset, exefs_header.section[i].size,
-                        exefs_header.section[i].name);
-
-                s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
-                                     sizeof(ExeFs_Header)+ncch_offset);
-                file.Seek(section_offset, 0);
-
-                // Section is compressed...
-                if (i == 0 && is_compressed) {
-                    // Read compressed .code section...
-                    std::unique_ptr<u8[]> temp_buffer;
-                    try {
-                        temp_buffer.reset(new u8[exefs_header.section[i].size]);
-                    } catch (std::bad_alloc&) {
-                        return ResultStatus::ErrorMemoryAllocationFailed;
-                    }
-                    file.ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
-
-                    // Decompress .code section...
-                    u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
-                        exefs_header.section[i].size);
-                    buffer.resize(decompressed_size);
-                    if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
-                        decompressed_size)) {
-                        return ResultStatus::ErrorInvalidFormat;
-                    }
-                    // Section is uncompressed...
+    if (!file->IsOpen())
+        return ResultStatus::Error;
+
+    LOG_DEBUG(Loader, "%d sections:", kMaxSections);
+    for (int i = 0; i < kMaxSections; i++) {
+        // Load the specified section...
+        if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
+            LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", i,
+                    exefs_header.section[i].offset, exefs_header.section[i].size,
+                    exefs_header.section[i].name);
+
+            s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
+                                 sizeof(ExeFs_Header)+ncch_offset);
+            file->Seek(section_offset, 0);
+
+            // Section is compressed...
+            if (i == 0 && is_compressed) {
+                // Read compressed .code section...
+                std::unique_ptr<u8[]> temp_buffer;
+                try {
+                    temp_buffer.reset(new u8[exefs_header.section[i].size]);
+                } catch (std::bad_alloc&) {
+                    return ResultStatus::ErrorMemoryAllocationFailed;
                 }
-                else {
-                    buffer.resize(exefs_header.section[i].size);
-                    file.ReadBytes(&buffer[0], exefs_header.section[i].size);
+                file->ReadBytes(&temp_buffer[0], exefs_header.section[i].size);
+
+                // Decompress .code section...
+                u32 decompressed_size = LZSS_GetDecompressedSize(&temp_buffer[0],
+                    exefs_header.section[i].size);
+                buffer.resize(decompressed_size);
+                if (!LZSS_Decompress(&temp_buffer[0], exefs_header.section[i].size, &buffer[0],
+                    decompressed_size)) {
+                    return ResultStatus::ErrorInvalidFormat;
                 }
-                return ResultStatus::Success;
+                // Section is uncompressed...
             }
+            else {
+                buffer.resize(exefs_header.section[i].size);
+                file->ReadBytes(&buffer[0], exefs_header.section[i].size);
+            }
+            return ResultStatus::Success;
         }
-    } else {
-        LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
-        return ResultStatus::Error;
     }
     return ResultStatus::ErrorNotUsed;
 }
 
 ResultStatus AppLoader_NCCH::Load() {
-    LOG_INFO(Loader, "Loading NCCH file %s...", filename.c_str());
-
     if (is_loaded)
         return ResultStatus::ErrorAlreadyLoaded;
 
-    FileUtil::IOFile file(filename, "rb");
-    if (file.IsOpen()) {
-        file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
+    if (!file->IsOpen())
+        return ResultStatus::Error;
 
-        // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
-        if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
-            LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
-            ncch_offset = 0x4000;
-            file.Seek(ncch_offset, 0);
-            file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
-        }
+    file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
 
-        // Verify we are loading the correct file type...
-        if (0 != memcmp(&ncch_header.magic, "NCCH", 4))
-            return ResultStatus::ErrorInvalidFormat;
+    // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
+    if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
+        LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
+        ncch_offset = 0x4000;
+        file->Seek(ncch_offset, 0);
+        file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
+    }
 
-        // Read ExHeader...
+    // Verify we are loading the correct file type...
+    if (0 != memcmp(&ncch_header.magic, "NCCH", 4))
+        return ResultStatus::ErrorInvalidFormat;
 
-        file.ReadBytes(&exheader_header, sizeof(ExHeader_Header));
+    // Read ExHeader...
 
-        is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
-        entry_point = exheader_header.codeset_info.text.address;
+    file->ReadBytes(&exheader_header, sizeof(ExHeader_Header));
 
-        LOG_INFO(Loader, "Name:            %s", exheader_header.codeset_info.name);
-        LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
-        LOG_DEBUG(Loader, "Entry point:     0x%08X", entry_point);
+    is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
+    entry_point = exheader_header.codeset_info.text.address;
 
-        // Read ExeFS...
+    LOG_INFO(Loader, "Name:            %s", exheader_header.codeset_info.name);
+    LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
+    LOG_DEBUG(Loader, "Entry point:     0x%08X", entry_point);
 
-        exefs_offset = ncch_header.exefs_offset * kBlockSize;
-        u32 exefs_size = ncch_header.exefs_size * kBlockSize;
+    // Read ExeFS...
 
-        LOG_DEBUG(Loader, "ExeFS offset:    0x%08X", exefs_offset);
-        LOG_DEBUG(Loader, "ExeFS size:      0x%08X", exefs_size);
+    exefs_offset = ncch_header.exefs_offset * kBlockSize;
+    u32 exefs_size = ncch_header.exefs_size * kBlockSize;
 
-        file.Seek(exefs_offset + ncch_offset, 0);
-        file.ReadBytes(&exefs_header, sizeof(ExeFs_Header));
+    LOG_DEBUG(Loader, "ExeFS offset:    0x%08X", exefs_offset);
+    LOG_DEBUG(Loader, "ExeFS size:      0x%08X", exefs_size);
 
-        LoadExec(); // Load the executable into memory for booting
+    file->Seek(exefs_offset + ncch_offset, 0);
+    file->ReadBytes(&exefs_header, sizeof(ExeFs_Header));
 
-        is_loaded = true; // Set state to loaded
+    LoadExec(); // Load the executable into memory for booting
 
-        return ResultStatus::Success;
-    } else {
-        LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
-    }
-    return ResultStatus::Error;
+    is_loaded = true; // Set state to loaded
+
+    return ResultStatus::Success;
 }
 
 ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const {
@@ -244,29 +225,26 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const {
 }
 
 ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
-    FileUtil::IOFile file(filename, "rb");
-    if (file.IsOpen()) {
-        // Check if the NCCH has a RomFS...
-        if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
-            u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
-            u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
+    if (!file->IsOpen())
+        return ResultStatus::Error;
 
-            LOG_DEBUG(Loader, "RomFS offset:    0x%08X", romfs_offset);
-            LOG_DEBUG(Loader, "RomFS size:      0x%08X", romfs_size);
+    // Check if the NCCH has a RomFS...
+    if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) {
+        u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
+        u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
 
-            buffer.resize(romfs_size);
+        LOG_DEBUG(Loader, "RomFS offset:    0x%08X", romfs_offset);
+        LOG_DEBUG(Loader, "RomFS size:      0x%08X", romfs_size);
 
-            file.Seek(romfs_offset, 0);
-            file.ReadBytes(&buffer[0], romfs_size);
+        buffer.resize(romfs_size);
 
-            return ResultStatus::Success;
-        }
-        LOG_DEBUG(Loader, "NCCH has no RomFS");
-        return ResultStatus::ErrorNotUsed;
-    } else {
-        LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
+        file->Seek(romfs_offset, 0);
+        file->ReadBytes(&buffer[0], romfs_size);
+
+        return ResultStatus::Success;
     }
-    return ResultStatus::Error;
+    LOG_DEBUG(Loader, "NCCH has no RomFS");
+    return ResultStatus::ErrorNotUsed;
 }
 
 u64 AppLoader_NCCH::GetProgramId() const {
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 578513f771..d9d68f1540 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -5,7 +5,6 @@
 #pragma once
 
 #include "common/common.h"
-#include "common/file_util.h"
 
 #include "core/loader/loader.h"
 
@@ -147,8 +146,7 @@ namespace Loader {
 /// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
 class AppLoader_NCCH final : public AppLoader {
 public:
-    AppLoader_NCCH(const std::string& filename);
-    ~AppLoader_NCCH() override;
+    AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
 
     /**
      * Load the application
@@ -213,9 +211,6 @@ private:
      */
     ResultStatus LoadExec() const;
 
-    std::string     filename;
-
-    bool            is_loaded = false;
     bool            is_compressed = false;
 
     u32             entry_point = 0;
-- 
GitLab