From 875f5eaad5d3e1a6303cdb9d767dd5d4ac86d988 Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Sun, 3 Dec 2023 14:02:23 -0800 Subject: [PATCH] file_sys: Add support for the BOSS ext save data archive. (#7231) --- src/core/file_sys/archive_backend.h | 1 + src/core/file_sys/archive_extsavedata.cpp | 13 ++++++++----- src/core/file_sys/archive_extsavedata.h | 14 ++++++++++---- src/core/frontend/applets/mii_selector.cpp | 3 ++- src/core/hle/service/fs/archive.cpp | 12 ++++++++---- src/core/hle/service/fs/archive.h | 1 + src/core/hle/service/ptm/ptm.cpp | 9 ++++++--- 7 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 0fada0f23c..8dc0f14d8d 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -41,6 +41,7 @@ class Path { public: Path() : type(LowPathType::Invalid) {} Path(const char* path) : type(LowPathType::Char), string(path) {} + Path(std::string path) : type(LowPathType::Char), string(std::move(path)) {} Path(std::vector binary_data) : type(LowPathType::Binary), binary(std::move(binary_data)) {} template Path(const std::array& binary_data) diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp index 7ab54d39c4..06c0334670 100644 --- a/src/core/file_sys/archive_extsavedata.cpp +++ b/src/core/file_sys/archive_extsavedata.cpp @@ -216,14 +216,16 @@ Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) { } ArchiveFactory_ExtSaveData::ArchiveFactory_ExtSaveData(const std::string& mount_location, - bool shared) - : shared(shared), mount_point(GetExtDataContainerPath(mount_location, shared)) { + ExtSaveDataType type_) + : type(type_), + mount_point(GetExtDataContainerPath(mount_location, type_ == ExtSaveDataType::Shared)) { LOG_DEBUG(Service_FS, "Directory {} set as base for ExtSaveData.", mount_point); } Path ArchiveFactory_ExtSaveData::GetCorrectedPath(const Path& path) { - if (!shared) + if (type != ExtSaveDataType::Shared) { return path; + } static constexpr u32 SharedExtDataHigh = 0x48000; @@ -242,11 +244,12 @@ Path ArchiveFactory_ExtSaveData::GetCorrectedPath(const Path& path) { ResultVal> ArchiveFactory_ExtSaveData::Open(const Path& path, u64 program_id) { - std::string fullpath = GetExtSaveDataPath(mount_point, GetCorrectedPath(path)) + "user/"; + const auto directory = type == ExtSaveDataType::Boss ? "boss/" : "user/"; + const auto fullpath = GetExtSaveDataPath(mount_point, GetCorrectedPath(path)) + directory; if (!FileUtil::Exists(fullpath)) { // TODO(Subv): Verify the archive behavior of SharedExtSaveData compared to ExtSaveData. // ExtSaveData seems to return FS_NotFound (120) when the archive doesn't exist. - if (!shared) { + if (type != ExtSaveDataType::Shared) { return ERR_NOT_FOUND_INVALID_STATE; } else { return ERR_NOT_FORMATTED; diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h index dec84ade9d..17ed459f47 100644 --- a/src/core/file_sys/archive_extsavedata.h +++ b/src/core/file_sys/archive_extsavedata.h @@ -15,10 +15,16 @@ namespace FileSys { +enum class ExtSaveDataType { + Normal, ///< Regular non-shared ext save data + Shared, ///< Shared ext save data + Boss, ///< SpotPass ext save data +}; + /// File system interface to the ExtSaveData archive class ArchiveFactory_ExtSaveData final : public ArchiveFactory { public: - ArchiveFactory_ExtSaveData(const std::string& mount_point, bool shared); + ArchiveFactory_ExtSaveData(const std::string& mount_point, ExtSaveDataType type_); std::string GetName() const override { return "ExtSaveData"; @@ -42,8 +48,8 @@ public: void WriteIcon(const Path& path, std::span icon); private: - bool shared; ///< Whether this archive represents an ExtSaveData archive or a SharedExtSaveData - /// archive + /// Type of ext save data archive being accessed. + ExtSaveDataType type; /** * This holds the full directory path for this archive, it is only set after a successful call @@ -59,7 +65,7 @@ private: template void serialize(Archive& ar, const unsigned int) { ar& boost::serialization::base_object(*this); - ar& shared; + ar& type; ar& mount_point; } friend class boost::serialization::access; diff --git a/src/core/frontend/applets/mii_selector.cpp b/src/core/frontend/applets/mii_selector.cpp index 13a864f68d..1dd6616490 100644 --- a/src/core/frontend/applets/mii_selector.cpp +++ b/src/core/frontend/applets/mii_selector.cpp @@ -19,7 +19,8 @@ std::vector LoadMiis() { std::vector miis; std::string nand_directory{FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)}; - FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); + FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, + FileSys::ExtSaveDataType::Shared); auto archive_result = extdata_archive_factory.Open(Service::PTM::ptm_shared_extdata_id, 0); if (archive_result.Succeeded()) { diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index ba98ce0455..ea5f0efd51 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -349,14 +349,18 @@ void ArchiveManager::RegisterArchiveTypes() { RegisterArchiveType(std::move(other_savedata_general_factory), ArchiveIdCode::OtherSaveDataGeneral); - auto extsavedata_factory = - std::make_unique(sdmc_directory, false); + auto extsavedata_factory = std::make_unique( + sdmc_directory, FileSys::ExtSaveDataType::Normal); RegisterArchiveType(std::move(extsavedata_factory), ArchiveIdCode::ExtSaveData); - auto sharedextsavedata_factory = - std::make_unique(nand_directory, true); + auto sharedextsavedata_factory = std::make_unique( + nand_directory, FileSys::ExtSaveDataType::Shared); RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData); + auto bossextsavedata_factory = std::make_unique( + sdmc_directory, FileSys::ExtSaveDataType::Boss); + RegisterArchiveType(std::move(bossextsavedata_factory), ArchiveIdCode::BossExtSaveData); + // Create the NCCH archive, basically a small variation of the RomFS archive auto savedatacheck_factory = std::make_unique(); RegisterArchiveType(std::move(savedatacheck_factory), ArchiveIdCode::NCCH); diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index f4604803b7..0f901a05b0 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -40,6 +40,7 @@ enum class ArchiveIdCode : u32 { SystemSaveData = 0x00000008, SDMC = 0x00000009, SDMCWriteOnly = 0x0000000A, + BossExtSaveData = 0x12345678, NCCH = 0x2345678A, OtherSaveDataGeneral = 0x567890B2, OtherSaveDataPermitted = 0x567890B4, diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 96cd944d23..213dc418b8 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp @@ -146,7 +146,8 @@ void Module::Interface::GetSystemTime(Kernel::HLERequestContext& ctx) { static void WriteGameCoinData(GameCoin gamecoin_data) { const std::string& nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); - FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); + FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, + FileSys::ExtSaveDataType::Shared); FileSys::Path archive_path(ptm_shared_extdata_id); auto archive_result = extdata_archive_factory.Open(archive_path, 0); @@ -179,7 +180,8 @@ static void WriteGameCoinData(GameCoin gamecoin_data) { static GameCoin ReadGameCoinData() { const std::string& nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); - FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); + FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, + FileSys::ExtSaveDataType::Shared); FileSys::Path archive_path(ptm_shared_extdata_id); auto archive_result = extdata_archive_factory.Open(archive_path, 0); @@ -209,7 +211,8 @@ Module::Module() { // Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't // exist const std::string& nand_directory = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); - FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, true); + FileSys::ArchiveFactory_ExtSaveData extdata_archive_factory(nand_directory, + FileSys::ExtSaveDataType::Shared); const FileSys::Path archive_path(ptm_shared_extdata_id); const auto archive_result = extdata_archive_factory.Open(archive_path, 0); // If the archive didn't exist, write the default game coin file