summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/mii
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service/mii')
-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
3 files changed, 116 insertions, 8 deletions
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 @@
#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) {
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 = {
// 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";
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 {
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