Просмотр исходного кода

mii: Implement Delete and Destroy file

Zach Hilman 7 лет назад
Родитель
Сommit
1aa2b99a98

+ 6 - 5
src/common/uuid.h

@@ -19,15 +19,16 @@ struct UUID {
     constexpr explicit UUID(const u128& id) : uuid{id} {}
     constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
 
-    explicit operator bool() const {
-        return uuid != INVALID_UUID;
+    constexpr explicit operator bool() const {
+        return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1];
     }
 
-    bool operator==(const UUID& rhs) const {
-        return uuid == rhs.uuid;
+    constexpr bool operator==(const UUID& rhs) const {
+        // TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20
+        return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
     }
 
-    bool operator!=(const UUID& rhs) const {
+    constexpr bool operator!=(const UUID& rhs) const {
         return !operator==(rhs);
     }
 

+ 79 - 8
src/core/hle/service/mii/mii.cpp

@@ -4,6 +4,8 @@
 
 #include <memory>
 
+#include <fmt/ostream.h>
+
 #include "common/logging/log.h"
 #include "common/string_util.h"
 #include "core/hle/ipc_helpers.h"
@@ -15,6 +17,10 @@
 
 namespace Service::Mii {
 
+constexpr ResultCode ERROR_INVALID_ARGUMENT{ErrorModule::Mii, 1};
+constexpr ResultCode ERROR_CANNOT_FIND_ENTRY{ErrorModule::Mii, 4};
+constexpr ResultCode ERROR_NOT_IN_TEST_MODE{ErrorModule::Mii, 99};
+
 class IDatabaseService final : public ServiceFramework<IDatabaseService> {
 public:
     explicit IDatabaseService() : ServiceFramework{"IDatabaseService"} {
@@ -35,8 +41,8 @@ public:
             {12, &IDatabaseService::Move, "Move"},
             {13, &IDatabaseService::AddOrReplace, "AddOrReplace"},
             {14, &IDatabaseService::Delete, "Delete"},
-            {15, nullptr, "DestroyFile"},
-            {16, nullptr, "DeleteFile"},
+            {15, &IDatabaseService::DestroyFile, "DestroyFile"},
+            {16, &IDatabaseService::DeleteFile, "DeleteFile"},
             {17, &IDatabaseService::Format, "Format"},
             {18, nullptr, "Import"},
             {19, nullptr, "Export"},
@@ -135,12 +141,33 @@ private:
 
     void BuildRandom(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
-        const auto random_params{rp.PopRaw<RandomParameters>()};
+        const auto [unknown1, unknown2, unknown3] = rp.PopRaw<RandomParameters>();
+
+        if (unknown1 > 3) {
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(ERROR_INVALID_ARGUMENT);
+            LOG_ERROR(Service_Mii, "Invalid unknown1 value: {}", unknown1);
+            return;
+        }
+
+        if (unknown2 > 2) {
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(ERROR_INVALID_ARGUMENT);
+            LOG_ERROR(Service_Mii, "Invalid unknown2 value: {}", unknown2);
+            return;
+        }
+
+        if (unknown3 > 3) {
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(ERROR_INVALID_ARGUMENT);
+            LOG_ERROR(Service_Mii, "Invalid unknown3 value: {}", unknown3);
+            return;
+        }
 
         LOG_DEBUG(Service_Mii, "called with param_1={:08X}, param_2={:08X}, param_3={:08X}",
-                  random_params.unknown_1, random_params.unknown_2, random_params.unknown_3);
+                  unknown1, unknown2, unknown3);
 
-        const auto info = db.CreateRandom(random_params);
+        const auto info = db.CreateRandom({unknown1, unknown2, unknown3});
         IPC::ResponseBuilder rb{ctx, 2 + sizeof(MiiInfo) / sizeof(u32)};
         rb.Push(RESULT_SUCCESS);
         rb.PushRaw<MiiInfo>(info);
@@ -150,6 +177,14 @@ private:
         IPC::RequestParser rp{ctx};
         const auto index{rp.PopRaw<u32>()};
 
+        if (index > 5) {
+            LOG_ERROR(Service_Mii, "invalid argument, index cannot be greater than 5 but is {:08X}",
+                      index);
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(ERROR_INVALID_ARGUMENT);
+            return;
+        }
+
         LOG_DEBUG(Service_Mii, "called with index={:08X}", index);
 
         const auto info = db.CreateDefault(index);
@@ -218,7 +253,14 @@ private:
     void Move(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
         const auto uuid{rp.PopRaw<Common::UUID>()};
-        const auto index{rp.PopRaw<u32>()};
+        const auto index{rp.PopRaw<s32>()};
+
+        if (index < 0) {
+            LOG_ERROR(Service_Mii, "Index cannot be negative but is {:08X}!", index);
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(ERROR_INVALID_ARGUMENT);
+            return;
+        }
 
         LOG_DEBUG(Service_Mii, "called with uuid={}, index={:08X}", uuid.FormatSwitch(), index);
 
@@ -252,8 +294,37 @@ private:
         const auto success = db.Remove(uuid);
 
         IPC::ResponseBuilder rb{ctx, 2};
-        // TODO(DarkLordZach): Find a better error code
-        rb.Push(success ? RESULT_SUCCESS : ResultCode(-1));
+        rb.Push(success ? RESULT_SUCCESS : ERROR_CANNOT_FIND_ENTRY);
+    }
+
+    void DestroyFile(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_Mii, "called");
+
+        if (!db.IsTestModeEnabled()) {
+            LOG_ERROR(Service_Mii, "Database is not in test mode -- cannot destory database file.");
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(ERROR_NOT_IN_TEST_MODE);
+            return;
+        }
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(db.DestroyFile());
+    }
+
+    void DeleteFile(Kernel::HLERequestContext& ctx) {
+        LOG_DEBUG(Service_Mii, "called");
+
+        if (!db.IsTestModeEnabled()) {
+            LOG_ERROR(Service_Mii, "Database is not in test mode -- cannot delete database file.");
+            IPC::ResponseBuilder rb{ctx, 2};
+            rb.Push(ERROR_NOT_IN_TEST_MODE);
+            return;
+        }
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(RESULT_SUCCESS);
+        rb.Push(db.DeleteFile());
     }
 
     void Format(Kernel::HLERequestContext& ctx) {

+ 27 - 0
src/core/hle/service/mii/mii_manager.cpp

@@ -32,6 +32,13 @@ 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};
 
+constexpr std::array<const char*, 4> SOURCE_NAMES{
+    "Database",
+    "Default",
+    "Account",
+    "Friend",
+};
+
 template <typename T, std::size_t SourceArraySize, std::size_t DestArraySize>
 std::array<T, DestArraySize> ResizeArray(const std::array<T, SourceArraySize>& in) {
     std::array<T, DestArraySize> out{};
@@ -167,6 +174,11 @@ MiiStoreData ConvertInfoToStoreData(const MiiInfo& info) {
 
 } // namespace
 
+std::ostream& operator<<(std::ostream& os,Source source) {
+    os << SOURCE_NAMES.at(static_cast<std::size_t>(source));
+    return os;
+}
+
 std::u16string MiiInfo::Name() const {
     return Common::UTF16StringFromFixedZeroTerminatedBuffer(name.data(), name.size());
 }
@@ -212,6 +224,10 @@ void MiiManager::ResetUpdatedFlag() {
     updated_flag = false;
 }
 
+bool MiiManager::IsTestModeEnabled() const {
+    return is_test_mode_enabled;
+}
+
 bool MiiManager::Empty() const {
     return Size() == 0;
 }
@@ -318,6 +334,17 @@ bool MiiManager::AddOrReplace(const MiiStoreData& data) {
     return true;
 }
 
+bool MiiManager::DestroyFile() {
+    database = DEFAULT_MII_DATABASE;
+    updated_flag = false;
+    return DeleteFile();
+}
+
+bool MiiManager::DeleteFile() {
+    const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + MII_SAVE_DATABASE_PATH;
+    return FileUtil::Exists(path) && FileUtil::Delete(path);
+}
+
 void MiiManager::WriteToFile() {
     const auto raw_path =
         FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000030";

+ 10 - 0
src/core/hle/service/mii/mii_manager.h

@@ -27,6 +27,8 @@ enum class Source : u32 {
     Friend = 3,
 };
 
+std::ostream& operator<<(std::ostream& os, Source source);
+
 struct MiiInfo {
     Common::UUID uuid;
     std::array<char16_t, 11> name;
@@ -183,6 +185,8 @@ struct MiiStoreBitFields {
     };
 };
 static_assert(sizeof(MiiStoreBitFields) == 0x1C, "MiiStoreBitFields has incorrect size.");
+static_assert(std::is_trivially_copyable_v<MiiStoreBitFields>,
+              "MiiStoreBitFields is not trivially copyable.");
 
 struct MiiStoreData {
     // This corresponds to the above structure MiiStoreBitFields. I did it like this because the
@@ -229,6 +233,8 @@ public:
     bool CheckUpdatedFlag() const;
     void ResetUpdatedFlag();
 
+    bool IsTestModeEnabled() const;
+
     bool Empty() const;
     bool Full() const;
 
@@ -248,6 +254,9 @@ public:
     bool Move(Common::UUID uuid, u32 new_index);
     bool AddOrReplace(const MiiStoreData& data);
 
+    bool DestroyFile();
+    bool DeleteFile();
+
 private:
     void WriteToFile();
     void ReadFromFile();
@@ -258,6 +267,7 @@ private:
 
     MiiDatabase database;
     bool updated_flag = false;
+    bool is_test_mode_enabled = false;
 };
 
 }; // namespace Service::Mii