From 2d33b2c55a46d848d5f544c772be1e016b39d517 Mon Sep 17 00:00:00 2001
From: Chloe Marcec <dmarcecguzman@gmail.com>
Date: Tue, 19 Jan 2021 20:56:18 +1100
Subject: [PATCH] acc: Stub StoreSaveDataThumbnail

Fixes ACA NEOGEO METAL SLUG hanging on boot.
---
 src/core/hle/service/acc/acc.cpp    | 61 +++++++++++++++++++++++++++--
 src/core/hle/service/acc/acc.h      |  5 +++
 src/core/hle/service/acc/acc_su.cpp |  2 +-
 src/core/hle/service/acc/acc_u0.cpp |  2 +-
 src/core/hle/service/acc/acc_u1.cpp |  2 +-
 5 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index bb07f6ccc4..3ec0e1ecab 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -32,9 +32,15 @@
 
 namespace Service::Account {
 
-constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30};
+constexpr ResultCode ERR_INVALID_USER_ID{ErrorModule::Account, 20};
+constexpr ResultCode ERR_INVALID_APPLICATION_ID{ErrorModule::Account, 22};
+constexpr ResultCode ERR_INVALID_BUFFER{ErrorModule::Account, 30};
+constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 31};
 constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
 
+// Thumbnails are hard coded to be at least this size
+constexpr std::size_t THUMBNAIL_SIZE = 0x24000;
+
 static std::string GetImagePath(Common::UUID uuid) {
     return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
            "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
@@ -369,7 +375,7 @@ protected:
         if (user_data.size() < sizeof(ProfileData)) {
             LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
             IPC::ResponseBuilder rb{ctx, 2};
-            rb.Push(ERR_INVALID_BUFFER_SIZE);
+            rb.Push(ERR_INVALID_BUFFER);
             return;
         }
 
@@ -402,7 +408,7 @@ protected:
         if (user_data.size() < sizeof(ProfileData)) {
             LOG_ERROR(Service_ACC, "ProfileData buffer too small!");
             IPC::ResponseBuilder rb{ctx, 2};
-            rb.Push(ERR_INVALID_BUFFER_SIZE);
+            rb.Push(ERR_INVALID_BUFFER);
             return;
         }
 
@@ -811,6 +817,55 @@ void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ct
     rb.Push(RESULT_SUCCESS);
 }
 
+void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto uuid = rp.PopRaw<Common::UUID>();
+
+    LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}", uuid.Format());
+
+    // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable
+    // way of confirming things like the TID, we're going to assume a non zero value for the time
+    // being.
+    constexpr u64 tid{1};
+    StoreSaveDataThumbnail(ctx, uuid, tid);
+}
+
+void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto uuid = rp.PopRaw<Common::UUID>();
+    const auto tid = rp.Pop<u64_le>();
+
+    LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}, tid={:016X}", uuid.Format(), tid);
+    StoreSaveDataThumbnail(ctx, uuid, tid);
+}
+
+void Module::Interface::StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx,
+                                               const Common::UUID& uuid, const u64 tid) {
+    IPC::ResponseBuilder rb{ctx, 2};
+
+    if (tid == 0) {
+        LOG_ERROR(Service_ACC, "TitleID is not valid!");
+        rb.Push(ERR_INVALID_APPLICATION_ID);
+        return;
+    }
+
+    if (!uuid) {
+        LOG_ERROR(Service_ACC, "User ID is not valid!");
+        rb.Push(ERR_INVALID_USER_ID);
+        return;
+    }
+    const auto thumbnail_size = ctx.GetReadBufferSize();
+    if (thumbnail_size != THUMBNAIL_SIZE) {
+        LOG_ERROR(Service_ACC, "Buffer size is empty! size={:X} expecting {:X}", thumbnail_size,
+                  THUMBNAIL_SIZE);
+        rb.Push(ERR_INVALID_BUFFER_SIZE);
+        return;
+    }
+
+    // TODO(ogniK): Construct save data thumbnail
+    rb.Push(RESULT_SUCCESS);
+}
+
 void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
     LOG_DEBUG(Service_ACC, "called");
     // 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 ab8edc0492..0e3ad8ec6f 100644
--- a/src/core/hle/service/acc/acc.h
+++ b/src/core/hle/service/acc/acc.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include "common/uuid.h"
 #include "core/hle/service/glue/manager.h"
 #include "core/hle/service/service.h"
 
@@ -36,9 +37,13 @@ public:
         void ListQualifiedUsers(Kernel::HLERequestContext& ctx);
         void LoadOpenContext(Kernel::HLERequestContext& ctx);
         void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx);
+        void StoreSaveDataThumbnailApplication(Kernel::HLERequestContext& ctx);
+        void StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& ctx);
 
     private:
         ResultCode InitializeApplicationInfoBase();
+        void StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx, const Common::UUID& uuid,
+                                    const u64 tid);
 
         enum class ApplicationType : u32_le {
             GameCard = 0,
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp
index d2bb8c2c8e..49b22583e3 100644
--- a/src/core/hle/service/acc/acc_su.cpp
+++ b/src/core/hle/service/acc/acc_su.cpp
@@ -29,7 +29,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
         {104, nullptr, "GetProfileUpdateNotifier"},
         {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
         {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+
-        {110, nullptr, "StoreSaveDataThumbnail"},
+        {110, &ACC_SU::StoreSaveDataThumbnailSystem, "StoreSaveDataThumbnail"},
         {111, nullptr, "ClearSaveDataThumbnail"},
         {112, nullptr, "LoadSaveDataThumbnail"},
         {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp
index 75a24f8f58..8d66d180d5 100644
--- a/src/core/hle/service/acc/acc_u0.cpp
+++ b/src/core/hle/service/acc/acc_u0.cpp
@@ -26,7 +26,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
         {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
         {102, nullptr, "AuthenticateApplicationAsync"},
         {103, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
-        {110, nullptr, "StoreSaveDataThumbnail"},
+        {110, &ACC_U0::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"},
         {111, nullptr, "ClearSaveDataThumbnail"},
         {120, nullptr, "CreateGuestLoginRequest"},
         {130, &ACC_U0::LoadOpenContext, "LoadOpenContext"}, // 5.0.0+
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp
index a4aa5316a9..951081cd00 100644
--- a/src/core/hle/service/acc/acc_u1.cpp
+++ b/src/core/hle/service/acc/acc_u1.cpp
@@ -29,7 +29,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
         {104, nullptr, "GetProfileUpdateNotifier"},
         {105, nullptr, "CheckNetworkServiceAvailabilityAsync"}, // 4.0.0+
         {106, nullptr, "GetProfileSyncNotifier"}, // 9.0.0+
-        {110, nullptr, "StoreSaveDataThumbnail"},
+        {110, &ACC_U1::StoreSaveDataThumbnailApplication, "StoreSaveDataThumbnail"},
         {111, nullptr, "ClearSaveDataThumbnail"},
         {112, nullptr, "LoadSaveDataThumbnail"},
         {113, nullptr, "GetSaveDataThumbnailExistence"}, // 5.0.0+