Merge pull request #2561 from wwylele/fs-rom
file_sys: change RomFS archive to Self NCCH archive
This commit is contained in:
		| @@ -20,10 +20,10 @@ set(SRCS | ||||
|             file_sys/archive_extsavedata.cpp | ||||
|             file_sys/archive_ncch.cpp | ||||
|             file_sys/archive_other_savedata.cpp | ||||
|             file_sys/archive_romfs.cpp | ||||
|             file_sys/archive_savedata.cpp | ||||
|             file_sys/archive_sdmc.cpp | ||||
|             file_sys/archive_sdmcwriteonly.cpp | ||||
|             file_sys/archive_selfncch.cpp | ||||
|             file_sys/archive_source_sd_savedata.cpp | ||||
|             file_sys/archive_systemsavedata.cpp | ||||
|             file_sys/disk_archive.cpp | ||||
| @@ -197,10 +197,10 @@ set(HEADERS | ||||
|             file_sys/archive_extsavedata.h | ||||
|             file_sys/archive_ncch.h | ||||
|             file_sys/archive_other_savedata.h | ||||
|             file_sys/archive_romfs.h | ||||
|             file_sys/archive_savedata.h | ||||
|             file_sys/archive_sdmc.h | ||||
|             file_sys/archive_sdmcwriteonly.h | ||||
|             file_sys/archive_selfncch.h | ||||
|             file_sys/archive_source_sd_savedata.h | ||||
|             file_sys/archive_systemsavedata.h | ||||
|             file_sys/directory_backend.h | ||||
|   | ||||
| @@ -1,43 +0,0 @@ | ||||
| // Copyright 2014 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <memory> | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/file_sys/archive_romfs.h" | ||||
| #include "core/file_sys/ivfc_archive.h" | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // FileSys namespace | ||||
|  | ||||
| namespace FileSys { | ||||
|  | ||||
| ArchiveFactory_RomFS::ArchiveFactory_RomFS(Loader::AppLoader& app_loader) { | ||||
|     // Load the RomFS from the app | ||||
|     if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) { | ||||
|         LOG_ERROR(Service_FS, "Unable to read RomFS!"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) { | ||||
|     auto archive = std::make_unique<IVFCArchive>(romfs_file, data_offset, data_size); | ||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||
| } | ||||
|  | ||||
| ResultCode ArchiveFactory_RomFS::Format(const Path& path, | ||||
|                                         const FileSys::ArchiveFormatInfo& format_info) { | ||||
|     LOG_ERROR(Service_FS, "Attempted to format a RomFS archive."); | ||||
|     // TODO: Verify error code | ||||
|     return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, | ||||
|                       ErrorLevel::Permanent); | ||||
| } | ||||
|  | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_RomFS::GetFormatInfo(const Path& path) const { | ||||
|     // TODO(Subv): Implement | ||||
|     LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); | ||||
|     return ResultCode(-1); | ||||
| } | ||||
|  | ||||
| } // namespace FileSys | ||||
							
								
								
									
										257
									
								
								src/core/file_sys/archive_selfncch.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								src/core/file_sys/archive_selfncch.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,257 @@ | ||||
| // Copyright 2017 Citra Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <array> | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "common/swap.h" | ||||
| #include "core/file_sys/archive_selfncch.h" | ||||
| #include "core/file_sys/errors.h" | ||||
| #include "core/file_sys/ivfc_archive.h" | ||||
|  | ||||
| //////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
| // FileSys namespace | ||||
|  | ||||
| namespace FileSys { | ||||
|  | ||||
| enum class SelfNCCHFilePathType : u32 { | ||||
|     RomFS = 0, | ||||
|     Code = 1, // This is not supported by SelfNCCHArchive but by archive 0x2345678E | ||||
|     ExeFS = 2, | ||||
|     UpdateRomFS = 5, // This is presumably for accessing the RomFS of the update patch. | ||||
| }; | ||||
|  | ||||
| struct SelfNCCHFilePath { | ||||
|     u32_le type; | ||||
|     std::array<char, 8> exefs_filename; | ||||
| }; | ||||
| static_assert(sizeof(SelfNCCHFilePath) == 12, "NCCHFilePath has wrong size!"); | ||||
|  | ||||
| // A read-only file created from a block of data. It only allows you to read the entire file at | ||||
| // once, in a single read operation. | ||||
| class ExeFSSectionFile final : public FileBackend { | ||||
| public: | ||||
|     explicit ExeFSSectionFile(std::shared_ptr<std::vector<u8>> data_) : data(std::move(data_)) {} | ||||
|  | ||||
|     ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override { | ||||
|         if (offset != 0) { | ||||
|             LOG_ERROR(Service_FS, "offset must be zero!"); | ||||
|             return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|         } | ||||
|  | ||||
|         if (length != data->size()) { | ||||
|             LOG_ERROR(Service_FS, "size must match the file size!"); | ||||
|             return ERROR_INCORRECT_EXEFS_READ_SIZE; | ||||
|         } | ||||
|  | ||||
|         std::memcpy(buffer, data->data(), data->size()); | ||||
|         return MakeResult<size_t>(data->size()); | ||||
|     } | ||||
|  | ||||
|     ResultVal<size_t> Write(u64 offset, size_t length, bool flush, | ||||
|                             const u8* buffer) const override { | ||||
|         LOG_ERROR(Service_FS, "The file is read-only!"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     u64 GetSize() const override { | ||||
|         return data->size(); | ||||
|     } | ||||
|  | ||||
|     bool SetSize(u64 size) const override { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool Close() const override { | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void Flush() const override {} | ||||
|  | ||||
| private: | ||||
|     std::shared_ptr<std::vector<u8>> data; | ||||
| }; | ||||
|  | ||||
| // SelfNCCHArchive represents the running application itself. From this archive the application can | ||||
| // open RomFS and ExeFS, excluding the .code section. | ||||
| class SelfNCCHArchive final : public ArchiveBackend { | ||||
| public: | ||||
|     explicit SelfNCCHArchive(const NCCHData& ncch_data_) : ncch_data(ncch_data_) {} | ||||
|  | ||||
|     std::string GetName() const override { | ||||
|         return "SelfNCCHArchive"; | ||||
|     } | ||||
|  | ||||
|     ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode&) const override { | ||||
|         // Note: SelfNCCHArchive doesn't check the open mode. | ||||
|  | ||||
|         if (path.GetType() != LowPathType::Binary) { | ||||
|             LOG_ERROR(Service_FS, "Path need to be Binary"); | ||||
|             return ERROR_INVALID_PATH; | ||||
|         } | ||||
|  | ||||
|         std::vector<u8> binary = path.AsBinary(); | ||||
|         if (binary.size() != sizeof(SelfNCCHFilePath)) { | ||||
|             LOG_ERROR(Service_FS, "Wrong path size %zu", binary.size()); | ||||
|             return ERROR_INVALID_PATH; | ||||
|         } | ||||
|  | ||||
|         SelfNCCHFilePath file_path; | ||||
|         std::memcpy(&file_path, binary.data(), sizeof(SelfNCCHFilePath)); | ||||
|  | ||||
|         switch (static_cast<SelfNCCHFilePathType>(file_path.type)) { | ||||
|         case SelfNCCHFilePathType::UpdateRomFS: | ||||
|             LOG_WARNING(Service_FS, "(STUBBED) open update RomFS"); | ||||
|             return OpenRomFS(); | ||||
|  | ||||
|         case SelfNCCHFilePathType::RomFS: | ||||
|             return OpenRomFS(); | ||||
|  | ||||
|         case SelfNCCHFilePathType::Code: | ||||
|             LOG_ERROR(Service_FS, "Reading the code section is not supported!"); | ||||
|             return ERROR_COMMAND_NOT_ALLOWED; | ||||
|  | ||||
|         case SelfNCCHFilePathType::ExeFS: { | ||||
|             const auto& raw = file_path.exefs_filename; | ||||
|             auto end = std::find(raw.begin(), raw.end(), '\0'); | ||||
|             std::string filename(raw.begin(), end); | ||||
|             return OpenExeFS(filename); | ||||
|         } | ||||
|         default: | ||||
|             LOG_ERROR(Service_FS, "Unknown file type %u!", static_cast<u32>(file_path.type)); | ||||
|             return ERROR_INVALID_PATH; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     ResultCode DeleteFile(const Path& path) const override { | ||||
|         LOG_ERROR(Service_FS, "Unsupported"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override { | ||||
|         LOG_ERROR(Service_FS, "Unsupported"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     ResultCode DeleteDirectory(const Path& path) const override { | ||||
|         LOG_ERROR(Service_FS, "Unsupported"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     ResultCode DeleteDirectoryRecursively(const Path& path) const override { | ||||
|         LOG_ERROR(Service_FS, "Unsupported"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     ResultCode CreateFile(const Path& path, u64 size) const override { | ||||
|         LOG_ERROR(Service_FS, "Unsupported"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     ResultCode CreateDirectory(const Path& path) const override { | ||||
|         LOG_ERROR(Service_FS, "Unsupported"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override { | ||||
|         LOG_ERROR(Service_FS, "Unsupported"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override { | ||||
|         LOG_ERROR(Service_FS, "Unsupported"); | ||||
|         return ERROR_UNSUPPORTED_OPEN_FLAGS; | ||||
|     } | ||||
|  | ||||
|     u64 GetFreeBytes() const override { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     ResultVal<std::unique_ptr<FileBackend>> OpenRomFS() const { | ||||
|         if (ncch_data.romfs_file) { | ||||
|             return MakeResult<std::unique_ptr<FileBackend>>(std::make_unique<IVFCFile>( | ||||
|                 ncch_data.romfs_file, ncch_data.romfs_offset, ncch_data.romfs_size)); | ||||
|         } else { | ||||
|             LOG_INFO(Service_FS, "Unable to read RomFS"); | ||||
|             return ERROR_ROMFS_NOT_FOUND; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     ResultVal<std::unique_ptr<FileBackend>> OpenExeFS(const std::string& filename) const { | ||||
|         if (filename == "icon") { | ||||
|             if (ncch_data.icon) { | ||||
|                 return MakeResult<std::unique_ptr<FileBackend>>( | ||||
|                     std::make_unique<ExeFSSectionFile>(ncch_data.icon)); | ||||
|             } | ||||
|  | ||||
|             LOG_WARNING(Service_FS, "Unable to read icon"); | ||||
|             return ERROR_EXEFS_SECTION_NOT_FOUND; | ||||
|         } | ||||
|  | ||||
|         if (filename == "logo") { | ||||
|             if (ncch_data.logo) { | ||||
|                 return MakeResult<std::unique_ptr<FileBackend>>( | ||||
|                     std::make_unique<ExeFSSectionFile>(ncch_data.logo)); | ||||
|             } | ||||
|  | ||||
|             LOG_WARNING(Service_FS, "Unable to read logo"); | ||||
|             return ERROR_EXEFS_SECTION_NOT_FOUND; | ||||
|         } | ||||
|  | ||||
|         if (filename == "banner") { | ||||
|             if (ncch_data.banner) { | ||||
|                 return MakeResult<std::unique_ptr<FileBackend>>( | ||||
|                     std::make_unique<ExeFSSectionFile>(ncch_data.banner)); | ||||
|             } | ||||
|  | ||||
|             LOG_WARNING(Service_FS, "Unable to read banner"); | ||||
|             return ERROR_EXEFS_SECTION_NOT_FOUND; | ||||
|         } | ||||
|  | ||||
|         LOG_ERROR(Service_FS, "Unknown ExeFS section %s!", filename.c_str()); | ||||
|         return ERROR_INVALID_PATH; | ||||
|     } | ||||
|  | ||||
|     NCCHData ncch_data; | ||||
| }; | ||||
|  | ||||
| ArchiveFactory_SelfNCCH::ArchiveFactory_SelfNCCH(Loader::AppLoader& app_loader) { | ||||
|     std::shared_ptr<FileUtil::IOFile> romfs_file_; | ||||
|     if (Loader::ResultStatus::Success == | ||||
|         app_loader.ReadRomFS(romfs_file_, ncch_data.romfs_offset, ncch_data.romfs_size)) { | ||||
|  | ||||
|         ncch_data.romfs_file = std::move(romfs_file_); | ||||
|     } | ||||
|  | ||||
|     std::vector<u8> buffer; | ||||
|  | ||||
|     if (Loader::ResultStatus::Success == app_loader.ReadIcon(buffer)) | ||||
|         ncch_data.icon = std::make_shared<std::vector<u8>>(std::move(buffer)); | ||||
|  | ||||
|     buffer.clear(); | ||||
|     if (Loader::ResultStatus::Success == app_loader.ReadLogo(buffer)) | ||||
|         ncch_data.logo = std::make_shared<std::vector<u8>>(std::move(buffer)); | ||||
|  | ||||
|     buffer.clear(); | ||||
|     if (Loader::ResultStatus::Success == app_loader.ReadBanner(buffer)) | ||||
|         ncch_data.banner = std::make_shared<std::vector<u8>>(std::move(buffer)); | ||||
| } | ||||
|  | ||||
| ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) { | ||||
|     auto archive = std::make_unique<SelfNCCHArchive>(ncch_data); | ||||
|     return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); | ||||
| } | ||||
|  | ||||
| ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&) { | ||||
|     LOG_ERROR(Service_FS, "Attempted to format a SelfNCCH archive."); | ||||
|     return ERROR_INVALID_PATH; | ||||
| } | ||||
|  | ||||
| ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&) const { | ||||
|     LOG_ERROR(Service_FS, "Attempted to get format info of a SelfNCCH archive"); | ||||
|     return ERROR_INVALID_PATH; | ||||
| } | ||||
|  | ||||
| } // namespace FileSys | ||||
| @@ -1,4 +1,4 @@ | ||||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Copyright 2017 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| @@ -17,22 +17,29 @@ | ||||
| 
 | ||||
| namespace FileSys { | ||||
| 
 | ||||
| /// File system interface to the RomFS archive
 | ||||
| class ArchiveFactory_RomFS final : public ArchiveFactory { | ||||
| struct NCCHData { | ||||
|     std::shared_ptr<std::vector<u8>> icon; | ||||
|     std::shared_ptr<std::vector<u8>> logo; | ||||
|     std::shared_ptr<std::vector<u8>> banner; | ||||
|     std::shared_ptr<FileUtil::IOFile> romfs_file; | ||||
|     u64 romfs_offset = 0; | ||||
|     u64 romfs_size = 0; | ||||
| }; | ||||
| 
 | ||||
| /// File system interface to the SelfNCCH archive
 | ||||
| class ArchiveFactory_SelfNCCH final : public ArchiveFactory { | ||||
| public: | ||||
|     explicit ArchiveFactory_RomFS(Loader::AppLoader& app_loader); | ||||
|     explicit ArchiveFactory_SelfNCCH(Loader::AppLoader& app_loader); | ||||
| 
 | ||||
|     std::string GetName() const override { | ||||
|         return "RomFS"; | ||||
|         return "SelfNCCH"; | ||||
|     } | ||||
|     ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; | ||||
|     ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; | ||||
|     ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path) const override; | ||||
| 
 | ||||
| private: | ||||
|     std::shared_ptr<FileUtil::IOFile> romfs_file; | ||||
|     u64 data_offset; | ||||
|     u64 data_size; | ||||
|     NCCHData ncch_data; | ||||
| }; | ||||
| 
 | ||||
| } // namespace FileSys
 | ||||
| @@ -39,5 +39,15 @@ const ResultCode ERROR_DIRECTORY_NOT_EMPTY(ErrorDescription::FS_DirectoryNotEmpt | ||||
| const ResultCode ERROR_GAMECARD_NOT_INSERTED(ErrorDescription::FS_GameCardNotInserted, | ||||
|                                              ErrorModule::FS, ErrorSummary::NotFound, | ||||
|                                              ErrorLevel::Status); | ||||
| const ResultCode ERROR_INCORRECT_EXEFS_READ_SIZE(ErrorDescription::FS_IncorrectExeFSReadSize, | ||||
|                                                  ErrorModule::FS, ErrorSummary::NotSupported, | ||||
|                                                  ErrorLevel::Usage); | ||||
| const ResultCode ERROR_ROMFS_NOT_FOUND(ErrorDescription::FS_RomFSNotFound, ErrorModule::FS, | ||||
|                                        ErrorSummary::NotFound, ErrorLevel::Status); | ||||
| const ResultCode ERROR_COMMAND_NOT_ALLOWED(ErrorDescription::FS_CommandNotAllowed, ErrorModule::FS, | ||||
|                                            ErrorSummary::WrongArgument, ErrorLevel::Permanent); | ||||
| const ResultCode ERROR_EXEFS_SECTION_NOT_FOUND(ErrorDescription::FS_ExeFSSectionNotFound, | ||||
|                                                ErrorModule::FS, ErrorSummary::NotFound, | ||||
|                                                ErrorLevel::Status); | ||||
|  | ||||
| } // namespace FileSys | ||||
|   | ||||
| @@ -20,6 +20,7 @@ enum class ErrorDescription : u32 { | ||||
|     OS_InvalidBufferDescriptor = 48, | ||||
|     MaxConnectionsReached = 52, | ||||
|     WrongAddress = 53, | ||||
|     FS_RomFSNotFound = 100, | ||||
|     FS_ArchiveNotMounted = 101, | ||||
|     FS_FileNotFound = 112, | ||||
|     FS_PathNotFound = 113, | ||||
| @@ -35,10 +36,13 @@ enum class ErrorDescription : u32 { | ||||
|     OutofRangeOrMisalignedAddress = | ||||
|         513, // TODO(purpasmart): Check if this name fits its actual usage | ||||
|     GPU_FirstInitialization = 519, | ||||
|     FS_ExeFSSectionNotFound = 567, | ||||
|     FS_CommandNotAllowed = 630, | ||||
|     FS_InvalidReadFlag = 700, | ||||
|     FS_InvalidPath = 702, | ||||
|     FS_WriteBeyondEnd = 705, | ||||
|     FS_UnsupportedOpenFlags = 760, | ||||
|     FS_IncorrectExeFSReadSize = 761, | ||||
|     FS_UnexpectedFileOrDirectory = 770, | ||||
|     InvalidSection = 1000, | ||||
|     TooLarge = 1001, | ||||
|   | ||||
| @@ -26,7 +26,7 @@ namespace FS { | ||||
|  | ||||
| /// Supported archive types | ||||
| enum class ArchiveIdCode : u32 { | ||||
|     RomFS = 0x00000003, | ||||
|     SelfNCCH = 0x00000003, | ||||
|     SaveData = 0x00000004, | ||||
|     ExtSaveData = 0x00000006, | ||||
|     SharedExtSaveData = 0x00000007, | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| #include <algorithm> | ||||
| #include <vector> | ||||
| #include "common/logging/log.h" | ||||
| #include "core/file_sys/archive_romfs.h" | ||||
| #include "core/file_sys/archive_selfncch.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/service/fs/archive.h" | ||||
| @@ -277,8 +277,8 @@ ResultStatus AppLoader_THREEDSX::Load() { | ||||
|  | ||||
|     Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); | ||||
|  | ||||
|     Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), | ||||
|                                      Service::FS::ArchiveIdCode::RomFS); | ||||
|     Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_SelfNCCH>(*this), | ||||
|                                      Service::FS::ArchiveIdCode::SelfNCCH); | ||||
|  | ||||
|     is_loaded = true; | ||||
|     return ResultStatus::Success; | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
| #include "common/logging/log.h" | ||||
| #include "common/string_util.h" | ||||
| #include "common/swap.h" | ||||
| #include "core/file_sys/archive_romfs.h" | ||||
| #include "core/file_sys/archive_selfncch.h" | ||||
| #include "core/hle/kernel/process.h" | ||||
| #include "core/hle/kernel/resource_limit.h" | ||||
| #include "core/hle/service/cfg/cfg.h" | ||||
| @@ -342,8 +342,8 @@ ResultStatus AppLoader_NCCH::Load() { | ||||
|     if (ResultStatus::Success != result) | ||||
|         return result; | ||||
|  | ||||
|     Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_RomFS>(*this), | ||||
|                                      Service::FS::ArchiveIdCode::RomFS); | ||||
|     Service::FS::RegisterArchiveType(std::make_unique<FileSys::ArchiveFactory_SelfNCCH>(*this), | ||||
|                                      Service::FS::ArchiveIdCode::SelfNCCH); | ||||
|  | ||||
|     ParseRegionLockoutInfo(); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user