diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp index 8e63b58b85..26db03fbab 100644 --- a/src/common/uuid.cpp +++ b/src/common/uuid.cpp @@ -1,4 +1,4 @@ -// Copyright 2018 Citra Emulator Project +// Copyright 2018 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/common/uuid.h b/src/common/uuid.h index 4a5e5fa7cc..b8864b34fb 100644 --- a/src/common/uuid.h +++ b/src/common/uuid.h @@ -1,9 +1,11 @@ -// Copyright 2018 Citra Emulator Project +// Copyright 2018 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once +#include + #include "common/common_types.h" namespace Common { @@ -33,7 +35,7 @@ struct UUID { static UUID Generate(); // Set the UUID to {0,0} to be considered an invalid user - void Invalidate() { + constexpr void Invalidate() { uuid = INVALID_UUID; } diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 767523dbca..49aa5908b4 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -13,7 +13,7 @@ namespace Service::Account { -using namespace Common; +using Common::UUID; struct UserRaw { UUID uuid; @@ -199,7 +199,7 @@ bool ProfileManager::UserExists(UUID uuid) const { bool ProfileManager::UserExistsIndex(std::size_t index) const { if (index >= MAX_USERS) return false; - return profiles[index].user_uuid.uuid != INVALID_UUID; + return profiles[index].user_uuid.uuid != Common::INVALID_UUID; } /// Opens a specific user @@ -293,7 +293,7 @@ bool ProfileManager::RemoveUser(UUID uuid) { bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) { const auto index = GetUserIndex(uuid); - if (!index || profile_new.user_uuid == UUID(INVALID_UUID)) { + if (!index || profile_new.user_uuid == UUID(Common::INVALID_UUID)) { return false; } @@ -324,7 +324,7 @@ void ProfileManager::ParseUserSaveFile() { } for (const auto& user : data.users) { - if (user.uuid == UUID(INVALID_UUID)) { + if (user.uuid == UUID(Common::INVALID_UUID)) { continue; } diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index 25dfd8d482..083c62b1e1 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -12,8 +12,10 @@ namespace Service::Mii { +namespace { + constexpr char MII_SAVE_DATABASE_PATH[] = "/system/save/8000000000000030/MiiDatabase.dat"; -constexpr std::array DEFAULT_MII_NAME = {'y', 'u', 'z', 'u', '\0'}; +constexpr std::array DEFAULT_MII_NAME = {u'y', u'u', u'z', u'u', u'\0'}; // This value was retrieved from HW test constexpr MiiStoreData DEFAULT_MII = { @@ -30,10 +32,10 @@ constexpr MiiStoreData DEFAULT_MII = { // Default values taken from multiple real databases const MiiDatabase DEFAULT_MII_DATABASE{Common::MakeMagic('N', 'F', 'D', 'B'), {}, {1}, 0, 0}; -template -std::array ResizeArray(const std::array& in) { - std::array out{}; - std::memcpy(out.data(), in.data(), sizeof(T) * std::min(s1, s2)); +template +std::array ResizeArray(const std::array& in) { + std::array out{}; + std::memcpy(out.data(), in.data(), sizeof(T) * std::min(SourceArraySize, DestArraySize)); return out; } @@ -163,12 +165,14 @@ MiiStoreData ConvertInfoToStoreData(const MiiInfo& info) { return out; } +} // namespace + std::u16string MiiInfo::Name() const { return Common::UTF16StringFromFixedZeroTerminatedBuffer(name.data(), name.size()); } bool operator==(const MiiInfo& lhs, const MiiInfo& rhs) { - return std::memcmp(&lhs, &rhs, sizeof(MiiInfo)); + return std::memcmp(&lhs, &rhs, sizeof(MiiInfo)) == 0; } bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs) { @@ -188,27 +192,15 @@ MiiInfo MiiManager::CreateRandom(RandomParameters params) { "(STUBBED) called with params={:08X}{:08X}{:08X}, returning default Mii", params.unknown_1, params.unknown_2, params.unknown_3); - auto new_mii = DEFAULT_MII; - - do { - new_mii.uuid = Common::UUID::Generate(); - } while (IndexOf(new_mii.uuid) == INVALID_INDEX); - - return ConvertStoreDataToInfo(new_mii); + return ConvertStoreDataToInfo(CreateMiiWithUniqueUUID()); } MiiInfo MiiManager::CreateDefault(u32 index) { - auto new_mii = DEFAULT_MII; + const auto new_mii = CreateMiiWithUniqueUUID(); - do { - new_mii.uuid = Common::UUID::Generate(); - } while (IndexOf(new_mii.uuid) == INVALID_INDEX); - - ASSERT(index < MAX_MIIS); - database.miis[index] = new_mii; - std::stable_partition(database.miis.begin(), database.miis.end(), - [](const MiiStoreData& elem) { return elem.uuid; }); + database.miis.at(index) = new_mii; + EnsureDatabasePartition(); return ConvertStoreDataToInfo(new_mii); } @@ -253,8 +245,7 @@ bool MiiManager::Remove(Common::UUID uuid) { return false; *iter = MiiStoreData{}; - std::stable_partition(database.miis.begin(), database.miis.end(), - [](const MiiStoreData& elem) { return elem.uuid; }); + EnsureDatabasePartition(); return true; } @@ -268,9 +259,9 @@ u32 MiiManager::IndexOf(Common::UUID uuid) const { return static_cast(std::distance(database.miis.begin(), iter)); } -u32 MiiManager::IndexOf(MiiInfo info) const { +u32 MiiManager::IndexOf(const MiiInfo& info) const { const auto iter = - std::find_if(database.miis.begin(), database.miis.end(), [info](const MiiStoreData& elem) { + std::find_if(database.miis.begin(), database.miis.end(), [&info](const MiiStoreData& elem) { return ConvertStoreDataToInfo(elem) == info; }); @@ -296,12 +287,11 @@ bool MiiManager::Move(Common::UUID uuid, u32 new_index) { database.miis[new_index] = moving; } - std::stable_partition(database.miis.begin(), database.miis.end(), - [](const MiiStoreData& elem) { return elem.uuid; }); + EnsureDatabasePartition(); return true; } -bool MiiManager::AddOrReplace(MiiStoreData data) { +bool MiiManager::AddOrReplace(const MiiStoreData& data) { const auto index = IndexOf(data.uuid); if (index == INVALID_INDEX) { @@ -341,7 +331,11 @@ void MiiManager::WriteToFile() { } save.Resize(sizeof(MiiDatabase)); - save.WriteBytes(&database, sizeof(MiiDatabase)); + if (save.WriteBytes(&database, sizeof(MiiDatabase)) != sizeof(MiiDatabase)) { + LOG_WARNING(Service_Mii, "Failed to write all data to save file... Data may be malformed " + "and/or regenerated on next run."); + save.Resize(0); + } } void MiiManager::ReadFromFile() { @@ -362,6 +356,20 @@ void MiiManager::ReadFromFile() { return; } + EnsureDatabasePartition(); +} + +MiiStoreData MiiManager::CreateMiiWithUniqueUUID() const { + auto new_mii = DEFAULT_MII; + + do { + new_mii.uuid = Common::UUID::Generate(); + } while (IndexOf(new_mii.uuid) == INVALID_INDEX); + + return new_mii; +} + +void MiiManager::EnsureDatabasePartition() { std::stable_partition(database.miis.begin(), database.miis.end(), [](const MiiStoreData& elem) { return elem.uuid; }); } diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index 069247cb6d..f7e3d2cf94 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h @@ -84,6 +84,8 @@ struct MiiInfo { std::u16string Name() const; }; static_assert(sizeof(MiiInfo) == 0x58, "MiiInfo has incorrect size."); +static_assert(std::has_unique_object_representations_v, + "All bits of MiiInfo must contribute to its value."); bool operator==(const MiiInfo& lhs, const MiiInfo& rhs); bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs); @@ -238,15 +240,19 @@ public: bool Remove(Common::UUID uuid); u32 IndexOf(Common::UUID uuid) const; - u32 IndexOf(MiiInfo info) const; + u32 IndexOf(const MiiInfo& info) const; bool Move(Common::UUID uuid, u32 new_index); - bool AddOrReplace(MiiStoreData data); + bool AddOrReplace(const MiiStoreData& data); private: void WriteToFile(); void ReadFromFile(); + MiiStoreData CreateMiiWithUniqueUUID() const; + + void EnsureDatabasePartition(); + MiiDatabase database; };