diff options
| -rw-r--r-- | src/core/hle/service/acc/acc.cpp | 124 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/acc/acc_su.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/acc/profile_manager.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/service/acc/profile_manager.h | 2 |
5 files changed, 130 insertions, 10 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index c01ee3eda..a7c55e116 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -31,6 +31,9 @@ | |||
| 31 | 31 | ||
| 32 | namespace Service::Account { | 32 | namespace Service::Account { |
| 33 | 33 | ||
| 34 | constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30}; | ||
| 35 | constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100}; | ||
| 36 | |||
| 34 | static std::string GetImagePath(Common::UUID uuid) { | 37 | static std::string GetImagePath(Common::UUID uuid) { |
| 35 | return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | 38 | return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + |
| 36 | "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; | 39 | "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; |
| @@ -41,20 +44,31 @@ static constexpr u32 SanitizeJPEGSize(std::size_t size) { | |||
| 41 | return static_cast<u32>(std::min(size, max_jpeg_image_size)); | 44 | return static_cast<u32>(std::min(size, max_jpeg_image_size)); |
| 42 | } | 45 | } |
| 43 | 46 | ||
| 44 | class IProfile final : public ServiceFramework<IProfile> { | 47 | class IProfileCommon : public ServiceFramework<IProfileCommon> { |
| 45 | public: | 48 | public: |
| 46 | explicit IProfile(Common::UUID user_id, ProfileManager& profile_manager) | 49 | explicit IProfileCommon(const char* name, bool editor_commands, Common::UUID user_id, |
| 47 | : ServiceFramework("IProfile"), profile_manager(profile_manager), user_id(user_id) { | 50 | ProfileManager& profile_manager) |
| 51 | : ServiceFramework(name), profile_manager(profile_manager), user_id(user_id) { | ||
| 48 | static const FunctionInfo functions[] = { | 52 | static const FunctionInfo functions[] = { |
| 49 | {0, &IProfile::Get, "Get"}, | 53 | {0, &IProfileCommon::Get, "Get"}, |
| 50 | {1, &IProfile::GetBase, "GetBase"}, | 54 | {1, &IProfileCommon::GetBase, "GetBase"}, |
| 51 | {10, &IProfile::GetImageSize, "GetImageSize"}, | 55 | {10, &IProfileCommon::GetImageSize, "GetImageSize"}, |
| 52 | {11, &IProfile::LoadImage, "LoadImage"}, | 56 | {11, &IProfileCommon::LoadImage, "LoadImage"}, |
| 53 | }; | 57 | }; |
| 58 | |||
| 54 | RegisterHandlers(functions); | 59 | RegisterHandlers(functions); |
| 60 | |||
| 61 | if (editor_commands) { | ||
| 62 | static const FunctionInfo editor_functions[] = { | ||
| 63 | {100, &IProfileCommon::Store, "Store"}, | ||
| 64 | {101, &IProfileCommon::StoreWithImage, "StoreWithImage"}, | ||
| 65 | }; | ||
| 66 | |||
| 67 | RegisterHandlers(editor_functions); | ||
| 68 | } | ||
| 55 | } | 69 | } |
| 56 | 70 | ||
| 57 | private: | 71 | protected: |
| 58 | void Get(Kernel::HLERequestContext& ctx) { | 72 | void Get(Kernel::HLERequestContext& ctx) { |
| 59 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); | 73 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); |
| 60 | ProfileBase profile_base{}; | 74 | ProfileBase profile_base{}; |
| @@ -127,10 +141,91 @@ private: | |||
| 127 | } | 141 | } |
| 128 | } | 142 | } |
| 129 | 143 | ||
| 130 | const ProfileManager& profile_manager; | 144 | void Store(Kernel::HLERequestContext& ctx) { |
| 145 | IPC::RequestParser rp{ctx}; | ||
| 146 | const auto base = rp.PopRaw<ProfileBase>(); | ||
| 147 | |||
| 148 | const auto user_data = ctx.ReadBuffer(); | ||
| 149 | |||
| 150 | LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}", | ||
| 151 | Common::StringFromFixedZeroTerminatedBuffer( | ||
| 152 | reinterpret_cast<const char*>(base.username.data()), base.username.size()), | ||
| 153 | base.timestamp, base.user_uuid.Format()); | ||
| 154 | |||
| 155 | if (user_data.size() < sizeof(ProfileData)) { | ||
| 156 | LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); | ||
| 157 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 158 | rb.Push(ERR_INVALID_BUFFER_SIZE); | ||
| 159 | return; | ||
| 160 | } | ||
| 161 | |||
| 162 | ProfileData data; | ||
| 163 | std::memcpy(&data, user_data.data(), sizeof(ProfileData)); | ||
| 164 | |||
| 165 | if (!profile_manager.SetProfileBaseAndData(user_id, base, data)) { | ||
| 166 | LOG_ERROR(Service_ACC, "Failed to update profile data and base!"); | ||
| 167 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 168 | rb.Push(ERR_FAILED_SAVE_DATA); | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | |||
| 172 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 173 | rb.Push(RESULT_SUCCESS); | ||
| 174 | } | ||
| 175 | |||
| 176 | void StoreWithImage(Kernel::HLERequestContext& ctx) { | ||
| 177 | IPC::RequestParser rp{ctx}; | ||
| 178 | const auto base = rp.PopRaw<ProfileBase>(); | ||
| 179 | |||
| 180 | const auto user_data = ctx.ReadBuffer(); | ||
| 181 | const auto image_data = ctx.ReadBuffer(1); | ||
| 182 | |||
| 183 | LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}", | ||
| 184 | Common::StringFromFixedZeroTerminatedBuffer( | ||
| 185 | reinterpret_cast<const char*>(base.username.data()), base.username.size()), | ||
| 186 | base.timestamp, base.user_uuid.Format()); | ||
| 187 | |||
| 188 | if (user_data.size() < sizeof(ProfileData)) { | ||
| 189 | LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); | ||
| 190 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 191 | rb.Push(ERR_INVALID_BUFFER_SIZE); | ||
| 192 | return; | ||
| 193 | } | ||
| 194 | |||
| 195 | ProfileData data; | ||
| 196 | std::memcpy(&data, user_data.data(), sizeof(ProfileData)); | ||
| 197 | |||
| 198 | FileUtil::IOFile image(GetImagePath(user_id), "wb"); | ||
| 199 | |||
| 200 | if (!image.IsOpen() || !image.Resize(image_data.size()) || | ||
| 201 | image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() || | ||
| 202 | !profile_manager.SetProfileBaseAndData(user_id, base, data)) { | ||
| 203 | LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!"); | ||
| 204 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 205 | rb.Push(ERR_FAILED_SAVE_DATA); | ||
| 206 | return; | ||
| 207 | } | ||
| 208 | |||
| 209 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 210 | rb.Push(RESULT_SUCCESS); | ||
| 211 | } | ||
| 212 | |||
| 213 | ProfileManager& profile_manager; | ||
| 131 | Common::UUID user_id; ///< The user id this profile refers to. | 214 | Common::UUID user_id; ///< The user id this profile refers to. |
| 132 | }; | 215 | }; |
| 133 | 216 | ||
| 217 | class IProfile final : public IProfileCommon { | ||
| 218 | public: | ||
| 219 | IProfile(Common::UUID user_id, ProfileManager& profile_manager) | ||
| 220 | : IProfileCommon("IProfile", false, user_id, profile_manager) {} | ||
| 221 | }; | ||
| 222 | |||
| 223 | class IProfileEditor final : public IProfileCommon { | ||
| 224 | public: | ||
| 225 | IProfileEditor(Common::UUID user_id, ProfileManager& profile_manager) | ||
| 226 | : IProfileCommon("IProfileEditor", true, user_id, profile_manager) {} | ||
| 227 | }; | ||
| 228 | |||
| 134 | class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { | 229 | class IManagerForApplication final : public ServiceFramework<IManagerForApplication> { |
| 135 | public: | 230 | public: |
| 136 | IManagerForApplication() : ServiceFramework("IManagerForApplication") { | 231 | IManagerForApplication() : ServiceFramework("IManagerForApplication") { |
| @@ -322,6 +417,17 @@ void Module::Interface::IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx | |||
| 322 | rb.Push(is_locked); | 417 | rb.Push(is_locked); |
| 323 | } | 418 | } |
| 324 | 419 | ||
| 420 | void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) { | ||
| 421 | IPC::RequestParser rp{ctx}; | ||
| 422 | Common::UUID user_id = rp.PopRaw<Common::UUID>(); | ||
| 423 | |||
| 424 | LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format()); | ||
| 425 | |||
| 426 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 427 | rb.Push(RESULT_SUCCESS); | ||
| 428 | rb.PushIpcInterface<IProfileEditor>(user_id, *profile_manager); | ||
| 429 | } | ||
| 430 | |||
| 325 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { | 431 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { |
| 326 | LOG_DEBUG(Service_ACC, "called"); | 432 | LOG_DEBUG(Service_ACC, "called"); |
| 327 | // A u8 is passed into this function which we can safely ignore. It's to determine if we have | 433 | // A u8 is passed into this function which we can safely ignore. It's to determine if we have |
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index f651773b7..7a7dc9ec6 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h | |||
| @@ -32,6 +32,7 @@ public: | |||
| 32 | void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx); | 32 | void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx); |
| 33 | void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx); | 33 | void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx); |
| 34 | void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); | 34 | void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); |
| 35 | void GetProfileEditor(Kernel::HLERequestContext& ctx); | ||
| 35 | 36 | ||
| 36 | private: | 37 | private: |
| 37 | ResultCode InitializeApplicationInfoBase(u64 process_id); | 38 | ResultCode InitializeApplicationInfoBase(u64 process_id); |
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 1b7ec3ed0..0d1663657 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp | |||
| @@ -41,7 +41,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 41 | {202, nullptr, "CancelUserRegistration"}, | 41 | {202, nullptr, "CancelUserRegistration"}, |
| 42 | {203, nullptr, "DeleteUser"}, | 42 | {203, nullptr, "DeleteUser"}, |
| 43 | {204, nullptr, "SetUserPosition"}, | 43 | {204, nullptr, "SetUserPosition"}, |
| 44 | {205, nullptr, "GetProfileEditor"}, | 44 | {205, &ACC_SU::GetProfileEditor, "GetProfileEditor"}, |
| 45 | {206, nullptr, "CompleteUserRegistrationForcibly"}, | 45 | {206, nullptr, "CompleteUserRegistrationForcibly"}, |
| 46 | {210, nullptr, "CreateFloatingRegistrationRequest"}, | 46 | {210, nullptr, "CreateFloatingRegistrationRequest"}, |
| 47 | {230, nullptr, "AuthenticateServiceAsync"}, | 47 | {230, nullptr, "AuthenticateServiceAsync"}, |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 49aa5908b..8f9986326 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -305,6 +305,17 @@ bool ProfileManager::SetProfileBase(UUID uuid, const ProfileBase& profile_new) { | |||
| 305 | return true; | 305 | return true; |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new, | ||
| 309 | const ProfileData& data_new) { | ||
| 310 | const auto index = GetUserIndex(uuid); | ||
| 311 | if (index.has_value() && SetProfileBase(uuid, profile_new)) { | ||
| 312 | profiles[*index].data = data_new; | ||
| 313 | return true; | ||
| 314 | } | ||
| 315 | |||
| 316 | return false; | ||
| 317 | } | ||
| 318 | |||
| 308 | void ProfileManager::ParseUserSaveFile() { | 319 | void ProfileManager::ParseUserSaveFile() { |
| 309 | FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | 320 | FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + |
| 310 | ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat", | 321 | ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat", |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index fd7abb541..5a6d28925 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -91,6 +91,8 @@ public: | |||
| 91 | 91 | ||
| 92 | bool RemoveUser(Common::UUID uuid); | 92 | bool RemoveUser(Common::UUID uuid); |
| 93 | bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new); | 93 | bool SetProfileBase(Common::UUID uuid, const ProfileBase& profile_new); |
| 94 | bool SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& profile_new, | ||
| 95 | const ProfileData& data_new); | ||
| 94 | 96 | ||
| 95 | private: | 97 | private: |
| 96 | void ParseUserSaveFile(); | 98 | void ParseUserSaveFile(); |