// Copyright 2014 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include #include #include #include "common/common_types.h" #include "common/file_util.h" #include "core/file_sys/romfs_reader.h" #include "core/hle/kernel/kernel.h" namespace Kernel { struct AddressMapping; class Process; } // namespace Kernel namespace Loader { /// File types supported by CTR enum class FileType { Error, Unknown, CCI, CXI, CIA, ELF, THREEDSX, // 3DSX }; /** * Identifies the type of a bootable file based on the magic value in its header. * @param file open file * @return FileType of file */ FileType IdentifyFile(FileUtil::IOFile& file); /** * Identifies the type of a bootable file based on the magic value in its header. * @param file_name path to file * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine * a filetype, and will never return FileType::Error. */ FileType IdentifyFile(const std::string& file_name); /** * Guess the type of a bootable file from its extension * @param extension String extension of bootable file * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine * a filetype, and will never return FileType::Error. */ FileType GuessFromExtension(const std::string& extension); /** * Convert a FileType into a string which can be displayed to the user. */ const char* GetFileTypeString(FileType type); /// Return type for functions in Loader namespace enum class ResultStatus { Success, Error, ErrorInvalidFormat, ErrorNotImplemented, ErrorNotLoaded, ErrorNotUsed, ErrorAlreadyLoaded, ErrorMemoryAllocationFailed, ErrorEncrypted, ErrorGbaTitle, }; constexpr u32 MakeMagic(char a, char b, char c, char d) { return a | b << 8 | c << 16 | d << 24; } /// Interface for loading an application class AppLoader : NonCopyable { public: explicit AppLoader(FileUtil::IOFile&& file) : file(std::move(file)) {} virtual ~AppLoader() {} /** * Returns the type of this file * @return FileType corresponding to the loaded file */ virtual FileType GetFileType() = 0; /** * Returns the preferred region codes of this file * @return A vector of the preferred region codes */ [[nodiscard]] virtual std::span GetPreferredRegions() const { return {}; } /** * Load the application and return the created Process instance * @param process The newly created process. * @return The status result of the operation. */ virtual ResultStatus Load(std::shared_ptr& process) = 0; /** * Loads the core version (FIRM title ID low) that this application needs. * This function defaults to 0x2 (NATIVE_FIRM) if it can't read the * information. * @returns A pair with the optional core version, and the status. */ virtual std::pair, ResultStatus> LoadCoreVersion() { return std::make_pair(0x2, ResultStatus::Success); } /** * Loads the memory mode that this application needs. * This function defaults to Dev1 (96MB allocated to the application) if it can't read the * information. * @returns A pair with the optional memory mode, and the status. */ virtual std::pair, ResultStatus> LoadKernelMemoryMode() { // 96MB allocated to the application. return std::make_pair(Kernel::MemoryMode::Dev1, ResultStatus::Success); } /** * Loads the N3DS hardware capabilities that this application uses. * It defaults to all disabled (O3DS) if it can't read the information. * @returns A pair with the optional N3DS hardware capabilities, and the status. */ virtual std::pair, ResultStatus> LoadNew3dsHwCapabilities() { return std::make_pair( Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy}, ResultStatus::Success); } /** * Get whether this application is executable. * @param out_executable Reference to store the executable flag into. * @return ResultStatus result of function */ virtual ResultStatus IsExecutable(bool& out_executable) { out_executable = true; return ResultStatus::Success; } /** * Get the code (typically .code section) of the application * @param buffer Reference to buffer to store data * @return ResultStatus result of function */ virtual ResultStatus ReadCode([[maybe_unused]] std::vector& buffer) { return ResultStatus::ErrorNotImplemented; } /** * Get the icon (typically icon section) of the application * @param buffer Reference to buffer to store data * @return ResultStatus result of function */ virtual ResultStatus ReadIcon([[maybe_unused]] std::vector& buffer) { return ResultStatus::ErrorNotImplemented; } /** * Get the banner (typically banner section) of the application * @param buffer Reference to buffer to store data * @return ResultStatus result of function */ virtual ResultStatus ReadBanner([[maybe_unused]] std::vector& buffer) { return ResultStatus::ErrorNotImplemented; } /** * Get the logo (typically logo section) of the application * @param buffer Reference to buffer to store data * @return ResultStatus result of function */ virtual ResultStatus ReadLogo([[maybe_unused]] std::vector& buffer) { return ResultStatus::ErrorNotImplemented; } /** * Get the program id of the application * @param out_program_id Reference to store program id into * @return ResultStatus result of function */ virtual ResultStatus ReadProgramId([[maybe_unused]] u64& out_program_id) { return ResultStatus::ErrorNotImplemented; } /** * Get the extdata id for the application * @param out_extdata_id Reference to store extdata id into * @return ResultStatus result of function */ virtual ResultStatus ReadExtdataId([[maybe_unused]] u64& out_extdata_id) { return ResultStatus::ErrorNotImplemented; } /** * Get the RomFS of the application * Since the RomFS can be huge, we return a file reference instead of copying to a buffer * @param romfs_file The file containing the RomFS * @return ResultStatus result of function */ virtual ResultStatus ReadRomFS( [[maybe_unused]] std::shared_ptr& romfs_file) { return ResultStatus::ErrorNotImplemented; } /** * Dump the RomFS of the applciation * @param target_path The target path to dump to * @return ResultStatus result of function */ virtual ResultStatus DumpRomFS([[maybe_unused]] const std::string& target_path) { return ResultStatus::ErrorNotImplemented; } /** * Get the update RomFS of the application * Since the RomFS can be huge, we return a file reference instead of copying to a buffer * @param romfs_file The file containing the RomFS * @return ResultStatus result of function */ virtual ResultStatus ReadUpdateRomFS( [[maybe_unused]] std::shared_ptr& romfs_file) { return ResultStatus::ErrorNotImplemented; } /** * Dump the update RomFS of the applciation * @param target_path The target path to dump to * @return ResultStatus result of function */ virtual ResultStatus DumpUpdateRomFS([[maybe_unused]] const std::string& target_path) { return ResultStatus::ErrorNotImplemented; } /** * Get the title of the application * @param title Reference to store the application title into * @return ResultStatus result of function */ virtual ResultStatus ReadTitle([[maybe_unused]] std::string& title) { return ResultStatus::ErrorNotImplemented; } protected: FileUtil::IOFile file; bool is_loaded = false; }; /** * Identifies a bootable file and return a suitable loader * @param filename String filename of bootable file * @return best loader for this file */ std::unique_ptr GetLoader(const std::string& filename); } // namespace Loader