summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Zach Hilman2018-12-27 20:54:44 -0500
committerGravatar Zach Hilman2019-04-25 08:07:57 -0400
commit1aa2b99a982e83022c9aae23c6a47eae119d21a4 (patch)
tree33f5c35625557c73998d48ca8f0d26dd0f986d84
parentmii: Implement IsUpdated command (IPC 0) (diff)
downloadyuzu-1aa2b99a982e83022c9aae23c6a47eae119d21a4.tar.gz
yuzu-1aa2b99a982e83022c9aae23c6a47eae119d21a4.tar.xz
yuzu-1aa2b99a982e83022c9aae23c6a47eae119d21a4.zip
mii: Implement Delete and Destroy file
-rw-r--r--src/common/uuid.h11
-rw-r--r--src/core/hle/service/mii/mii.cpp87
-rw-r--r--src/core/hle/service/mii/mii_manager.cpp27
-rw-r--r--src/core/hle/service/mii/mii_manager.h10
4 files changed, 122 insertions, 13 deletions
diff --git a/src/common/uuid.h b/src/common/uuid.h
index b8864b34f..f6ad064fb 100644
--- a/src/common/uuid.h
+++ b/src/common/uuid.h
@@ -19,15 +19,16 @@ struct UUID {
19 constexpr explicit UUID(const u128& id) : uuid{id} {} 19 constexpr explicit UUID(const u128& id) : uuid{id} {}
20 constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {} 20 constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
21 21
22 explicit operator bool() const { 22 constexpr explicit operator bool() const {
23 return uuid != INVALID_UUID; 23 return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1];
24 } 24 }
25 25
26 bool operator==(const UUID& rhs) const { 26 constexpr bool operator==(const UUID& rhs) const {
27 return uuid == rhs.uuid; 27 // TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20
28 return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
28 } 29 }
29 30
30 bool operator!=(const UUID& rhs) const { 31 constexpr bool operator!=(const UUID& rhs) const {
31 return !operator==(rhs); 32 return !operator==(rhs);
32 } 33 }
33 34
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index 39e4e937a..ce84e25ed 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -4,6 +4,8 @@
4 4
5#include <memory> 5#include <memory>
6 6
7#include <fmt/ostream.h>
8
7#include "common/logging/log.h" 9#include "common/logging/log.h"
8#include "common/string_util.h" 10#include "common/string_util.h"
9#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
@@ -15,6 +17,10 @@
15 17
16namespace Service::Mii { 18namespace Service::Mii {
17 19
20constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::Mii, 1};
21constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4};
22constexpr ResultCode ERROR_NOT_IN_TEST_MODE{ErrorModule::Mii, 99};
23
18class IDatabaseService final : public ServiceFramework<IDatabaseService> { 24class IDatabaseService final : public ServiceFramework<IDatabaseService> {
19public: 25public:
20 explicit IDatabaseService() : ServiceFramework{"IDatabaseService"} { 26 explicit IDatabaseService() : ServiceFramework{"IDatabaseService"} {
@@ -35,8 +41,8 @@ public:
35 {12, &IDatabaseService::Move, "Move"}, 41 {12, &IDatabaseService::Move, "Move"},
36 {13, &IDatabaseService::AddOrReplace, "AddOrReplace"}, 42 {13, &IDatabaseService::AddOrReplace, "AddOrReplace"},
37 {14, &IDatabaseService::Delete, "Delete"}, 43 {14, &IDatabaseService::Delete, "Delete"},
38 {15, nullptr, "DestroyFile"}, 44 {15, &IDatabaseService::DestroyFile, "DestroyFile"},
39 {16, nullptr, "DeleteFile"}, 45 {16, &IDatabaseService::DeleteFile, "DeleteFile"},
40 {17, &IDatabaseService::Format, "Format"}, 46 {17, &IDatabaseService::Format, "Format"},
41 {18, nullptr, "Import"}, 47 {18, nullptr, "Import"},
42 {19, nullptr, "Export"}, 48 {19, nullptr, "Export"},
@@ -135,12 +141,33 @@ private:
135 141
136 void BuildRandom(Kernel::HLERequestContext& ctx) { 142 void BuildRandom(Kernel::HLERequestContext& ctx) {
137 IPC::RequestParser rp{ctx}; 143 IPC::RequestParser rp{ctx};
138 const auto random_params{rp.PopRaw<RandomParameters>()}; 144 const auto [unknown1, unknown2, unknown3] = rp.PopRaw<RandomParameters>();
145
146 if (unknown1 > 3) {
147 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(ERROR_INVALID_ARGUMENT);
149 LOG_ERROR(Service_Mii, "Invalid unknown1 value: {}", unknown1);
150 return;
151 }
152
153 if (unknown2 > 2) {
154 IPC::ResponseBuilder rb{ctx, 2};
155 rb.Push(ERROR_INVALID_ARGUMENT);
156 LOG_ERROR(Service_Mii, "Invalid unknown2 value: {}", unknown2);
157 return;
158 }
159
160 if (unknown3 > 3) {
161 IPC::ResponseBuilder rb{ctx, 2};
162 rb.Push(ERROR_INVALID_ARGUMENT);
163 LOG_ERROR(Service_Mii, "Invalid unknown3 value: {}", unknown3);
164 return;
165 }
139 166
140 LOG_DEBUG(Service_Mii, "called with param_1={:08X}, param_2={:08X}, param_3={:08X}", 167 LOG_DEBUG(Service_Mii, "called with param_1={:08X}, param_2={:08X}, param_3={:08X}",
141 random_params.unknown_1, random_params.unknown_2, random_params.unknown_3); 168 unknown1, unknown2, unknown3);
142 169
143 const auto info = db.CreateRandom(random_params); 170 const auto info = db.CreateRandom({unknown1, unknown2, unknown3});
144 IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)}; 171 IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)};
145 rb.Push(RESULT_SUCCESS); 172 rb.Push(RESULT_SUCCESS);
146 rb.PushRaw<MiiInfo>(info); 173 rb.PushRaw<MiiInfo>(info);
@@ -150,6 +177,14 @@ private:
150 IPC::RequestParser rp{ctx}; 177 IPC::RequestParser rp{ctx};
151 const auto index{rp.PopRaw<u32>()}; 178 const auto index{rp.PopRaw<u32>()};
152 179
180 if (index > 5) {
181 LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}",
182 index);
183 IPC::ResponseBuilder rb{ctx, 2};
184 rb.Push(ERROR_INVALID_ARGUMENT);
185 return;
186 }
187
153 LOG_DEBUG(Service_Mii, "called with index={:08X}", index); 188 LOG_DEBUG(Service_Mii, "called with index={:08X}", index);
154 189
155 const auto info = db.CreateDefault(index); 190 const auto info = db.CreateDefault(index);
@@ -218,7 +253,14 @@ private:
218 void Move(Kernel::HLERequestContext& ctx) { 253 void Move(Kernel::HLERequestContext& ctx) {
219 IPC::RequestParser rp{ctx}; 254 IPC::RequestParser rp{ctx};
220 const auto uuid{rp.PopRaw<Common::UUID>()}; 255 const auto uuid{rp.PopRaw<Common::UUID>()};
221 const auto index{rp.PopRaw<u32>()}; 256 const auto index{rp.PopRaw<s32>()};
257
258 if (index < 0) {
259 LOG_ERROR(Service_Mii, "Index cannot be negative but is {:08X}!", index);
260 IPC::ResponseBuilder rb{ctx, 2};
261 rb.Push(ERROR_INVALID_ARGUMENT);
262 return;
263 }
222 264
223 LOG_DEBUG(Service_Mii, "called with uuid={}, index={:08X}", uuid.FormatSwitch(), index); 265 LOG_DEBUG(Service_Mii, "called with uuid={}, index={:08X}", uuid.FormatSwitch(), index);
224 266
@@ -252,8 +294,37 @@ private:
252 const auto success = db.Remove(uuid); 294 const auto success = db.Remove(uuid);
253 295
254 IPC::ResponseBuilder rb{ctx, 2}; 296 IPC::ResponseBuilder rb{ctx, 2};
255 // TODO(DarkLordZach): Find a better error code 297 rb.Push(success ? RESULT_SUCCESS : ERROR_CANNOT_FIND_ENTRY);
256 rb.Push(success ? RESULT_SUCCESS : ResultCode(-1)); 298 }
299
300 void DestroyFile(Kernel::HLERequestContext& ctx) {
301 LOG_DEBUG(Service_Mii, "called");
302
303 if (!db.IsTestModeEnabled()) {
304 LOG_ERROR(Service_Mii, "Database is not in test mode -- cannot destory database file.");
305 IPC::ResponseBuilder rb{ctx, 2};
306 rb.Push(ERROR_NOT_IN_TEST_MODE);
307 return;
308 }
309
310 IPC::ResponseBuilder rb{ctx, 3};
311 rb.Push(RESULT_SUCCESS);
312 rb.Push(db.DestroyFile());
313 }
314
315 void DeleteFile(Kernel::HLERequestContext& ctx) {
316 LOG_DEBUG(Service_Mii, "called");
317
318 if (!db.IsTestModeEnabled()) {
319 LOG_ERROR(Service_Mii, "Database is not in test mode -- cannot delete database file.");
320 IPC::ResponseBuilder rb{ctx, 2};
321 rb.Push(ERROR_NOT_IN_TEST_MODE);
322 return;
323 }
324
325 IPC::ResponseBuilder rb{ctx, 3};
326 rb.Push(RESULT_SUCCESS);
327 rb.Push(db.DeleteFile());
257 } 328 }
258 329
259 void Format(Kernel::HLERequestContext& ctx) { 330 void Format(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp
index 7011ea2bd..04fc2180b 100644
--- a/src/core/hle/service/mii/mii_manager.cpp
+++ b/src/core/hle/service/mii/mii_manager.cpp
@@ -32,6 +32,13 @@ constexpr MiiStoreData DEFAULT_MII = {
32// Default values taken from multiple real databases 32// Default values taken from multiple real databases
33const MiiDatabase DEFAULT_MII_DATABASE{Common::MakeMagic('N', 'F', 'D', 'B'), {}, {1}, 0, 0}; 33const MiiDatabase DEFAULT_MII_DATABASE{Common::MakeMagic('N', 'F', 'D', 'B'), {}, {1}, 0, 0};
34 34
35constexpr std::array<const char*, 4> SOURCE_NAMES{
36 "Database",
37 "Default",
38 "Account",
39 "Friend",
40};
41
35template <typename T, std::size_t SourceArraySize, std::size_t DestArraySize> 42template <typename T, std::size_t SourceArraySize, std::size_t DestArraySize>
36std::array<T, DestArraySize> ResizeArray(const std::array<T, SourceArraySize>& in) { 43std::array<T, DestArraySize> ResizeArray(const std::array<T, SourceArraySize>& in) {
37 std::array<T, DestArraySize> out{}; 44 std::array<T, DestArraySize> out{};
@@ -167,6 +174,11 @@ MiiStoreData ConvertInfoToStoreData(const MiiInfo& info) {
167 174
168} // namespace 175} // namespace
169 176
177std::ostream& operator<<(std::ostream& os,Source source) {
178 os << SOURCE_NAMES.at(static_cast<std::size_t>(source));
179 return os;
180}
181
170std::u16string MiiInfo::Name() const { 182std::u16string MiiInfo::Name() const {
171 return Common::UTF16StringFromFixedZeroTerminatedBuffer(name.data(), name.size()); 183 return Common::UTF16StringFromFixedZeroTerminatedBuffer(name.data(), name.size());
172} 184}
@@ -212,6 +224,10 @@ void MiiManager::ResetUpdatedFlag() {
212 updated_flag = false; 224 updated_flag = false;
213} 225}
214 226
227bool MiiManager::IsTestModeEnabled() const {
228 return is_test_mode_enabled;
229}
230
215bool MiiManager::Empty() const { 231bool MiiManager::Empty() const {
216 return Size() == 0; 232 return Size() == 0;
217} 233}
@@ -318,6 +334,17 @@ bool MiiManager::AddOrReplace(const MiiStoreData& data) {
318 return true; 334 return true;
319} 335}
320 336
337bool MiiManager::DestroyFile() {
338 database = DEFAULT_MII_DATABASE;
339 updated_flag = false;
340 return DeleteFile();
341}
342
343bool MiiManager::DeleteFile() {
344 const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + MII_SAVE_DATABASE_PATH;
345 return FileUtil::Exists(path) && FileUtil::Delete(path);
346}
347
321void MiiManager::WriteToFile() { 348void MiiManager::WriteToFile() {
322 const auto raw_path = 349 const auto raw_path =
323 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000030"; 350 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000030";
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h
index bf955930d..38ad78a0d 100644
--- a/src/core/hle/service/mii/mii_manager.h
+++ b/src/core/hle/service/mii/mii_manager.h
@@ -27,6 +27,8 @@ enum class Source : u32 {
27 Friend = 3, 27 Friend = 3,
28}; 28};
29 29
30std::ostream& operator<<(std::ostream& os, Source source);
31
30struct MiiInfo { 32struct MiiInfo {
31 Common::UUID uuid; 33 Common::UUID uuid;
32 std::array<char16_t, 11> name; 34 std::array<char16_t, 11> name;
@@ -183,6 +185,8 @@ struct MiiStoreBitFields {
183 }; 185 };
184}; 186};
185static_assert(sizeof(MiiStoreBitFields) == 0x1C, "MiiStoreBitFields has incorrect size."); 187static_assert(sizeof(MiiStoreBitFields) == 0x1C, "MiiStoreBitFields has incorrect size.");
188static_assert(std::is_trivially_copyable_v<MiiStoreBitFields>,
189 "MiiStoreBitFields is not trivially copyable.");
186 190
187struct MiiStoreData { 191struct MiiStoreData {
188 // This corresponds to the above structure MiiStoreBitFields. I did it like this because the 192 // This corresponds to the above structure MiiStoreBitFields. I did it like this because the
@@ -229,6 +233,8 @@ public:
229 bool CheckUpdatedFlag() const; 233 bool CheckUpdatedFlag() const;
230 void ResetUpdatedFlag(); 234 void ResetUpdatedFlag();
231 235
236 bool IsTestModeEnabled() const;
237
232 bool Empty() const; 238 bool Empty() const;
233 bool Full() const; 239 bool Full() const;
234 240
@@ -248,6 +254,9 @@ public:
248 bool Move(Common::UUID uuid, u32 new_index); 254 bool Move(Common::UUID uuid, u32 new_index);
249 bool AddOrReplace(const MiiStoreData& data); 255 bool AddOrReplace(const MiiStoreData& data);
250 256
257 bool DestroyFile();
258 bool DeleteFile();
259
251private: 260private:
252 void WriteToFile(); 261 void WriteToFile();
253 void ReadFromFile(); 262 void ReadFromFile();
@@ -258,6 +267,7 @@ private:
258 267
259 MiiDatabase database; 268 MiiDatabase database;
260 bool updated_flag = false; 269 bool updated_flag = false;
270 bool is_test_mode_enabled = false;
261}; 271};
262 272
263}; // namespace Service::Mii 273}; // namespace Service::Mii