From 086564c3c88d8006670199b3aba5977c07f16261 Mon Sep 17 00:00:00 2001
From: riperiperi <rhy3756547@hotmail.com>
Date: Fri, 6 Oct 2023 23:23:39 +0100
Subject: [PATCH] HLE: Fix Mii crc generation and minor issues (#5766)

* HLE: Fix Mii crc generation

Validating CRCs for data and device involves calculating the crc of all data including the crc being checked, which should then be 0.

The crc should be _generated_ on all data _before_ the crc in the struct. It shouldn't include the crcs themselves.

This fixes all generated miis (eg. default) having invalid crcs. This does not affect mii maker, as that generates its own charinfo.

Does not fix MK8D crash.

* Fix other mii issues

* Fully define all fields for Nickname and Ver3StoreData

Fixes an issue where the nickname for a mii would only have the first character on some method calls.

* Add Array96 type
---
 src/Ryujinx.Common/Memory/StructArrayHelpers.cs      | 12 ++++++++++++
 src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs     |  2 +-
 src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs   |  7 ++++---
 src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs   |  7 ++++---
 src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs  |  9 +++++++--
 .../HOS/Services/Mii/Types/Ver3StoreData.cs          |  8 +++++---
 6 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/src/Ryujinx.Common/Memory/StructArrayHelpers.cs b/src/Ryujinx.Common/Memory/StructArrayHelpers.cs
index 65956ed326..807bd69c34 100644
--- a/src/Ryujinx.Common/Memory/StructArrayHelpers.cs
+++ b/src/Ryujinx.Common/Memory/StructArrayHelpers.cs
@@ -756,6 +756,18 @@ namespace Ryujinx.Common.Memory
         public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
     }
 
+    public struct Array96<T> : IArray<T> where T : unmanaged
+    {
+        T _e0;
+        Array64<T> _other;
+        Array31<T> _other2;
+        public readonly int Length => 96;
+        public ref T this[int index] => ref AsSpan()[index];
+
+        [Pure]
+        public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
+    }
+
     public struct Array127<T> : IArray<T> where T : unmanaged
     {
         T _e0;
diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs b/src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs
index d9bcecee1c..5041dc8825 100644
--- a/src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Mii/DatabaseImpl.cs
@@ -290,7 +290,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii
         {
             coreData = new CoreData();
 
-            if (charInfo.IsValid())
+            if (!charInfo.IsValid())
             {
                 return ResultCode.InvalidCharInfo;
             }
diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs b/src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs
index 00e49ecb99..4f6e289e2e 100644
--- a/src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Mii/Types/CoreData.cs
@@ -1,4 +1,5 @@
-using System;
+using Ryujinx.Common.Memory;
+using System;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using static Ryujinx.HLE.HOS.Services.Mii.Types.RandomMiiConstants;
@@ -10,9 +11,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
     {
         public const int Size = 0x30;
 
-        private byte _storage;
+        private Array48<byte> _storage;
 
-        public Span<byte> Storage => MemoryMarshal.CreateSpan(ref _storage, Size);
+        public Span<byte> Storage => _storage.AsSpan();
 
         [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 0x18)]
         public struct ElementInfo
diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs b/src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs
index dc21d8e567..6665ca6d41 100644
--- a/src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Mii/Types/Nickname.cs
@@ -1,4 +1,5 @@
-using System;
+using Ryujinx.Common.Memory;
+using System;
 using System.Runtime.InteropServices;
 using System.Text;
 
@@ -10,12 +11,12 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
         public const int CharCount = 10;
         private const int SizeConst = (CharCount + 1) * 2;
 
-        private byte _storage;
+        private Array22<byte> _storage;
 
         public static Nickname Default => FromString("no name");
         public static Nickname Question => FromString("???");
 
-        public Span<byte> Raw => MemoryMarshal.CreateSpan(ref _storage, SizeConst);
+        public Span<byte> Raw => _storage.AsSpan();
 
         private ReadOnlySpan<ushort> Characters => MemoryMarshal.Cast<byte, ushort>(Raw);
 
diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs b/src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs
index 994f6b7ce1..178b483187 100644
--- a/src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Mii/Types/StoreData.cs
@@ -62,7 +62,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
 
         private ushort CalculateDataCrc()
         {
-            return Helper.CalculateCrc16(AsSpanWithoutDeviceCrc(), 0, true);
+            return Helper.CalculateCrc16(AsSpanWithoutCrcs(), 0, true);
         }
 
         private ushort CalculateDeviceCrc()
@@ -71,7 +71,7 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
 
             ushort deviceIdCrc16 = Helper.CalculateCrc16(SpanHelpers.AsByteSpan(ref deviceId), 0, false);
 
-            return Helper.CalculateCrc16(AsSpan(), deviceIdCrc16, true);
+            return Helper.CalculateCrc16(AsSpanWithoutDeviceCrc(), deviceIdCrc16, true);
         }
 
         private ReadOnlySpan<byte> AsSpan()
@@ -84,6 +84,11 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
             return AsSpan()[..(Size - 2)];
         }
 
+        private ReadOnlySpan<byte> AsSpanWithoutCrcs()
+        {
+            return AsSpan()[..(Size - 4)];
+        }
+
         public static StoreData BuildDefault(UtilityImpl utilImpl, uint index)
         {
             StoreData result = new()
diff --git a/src/Ryujinx.HLE/HOS/Services/Mii/Types/Ver3StoreData.cs b/src/Ryujinx.HLE/HOS/Services/Mii/Types/Ver3StoreData.cs
index 70bb348b57..1c7db8e66b 100644
--- a/src/Ryujinx.HLE/HOS/Services/Mii/Types/Ver3StoreData.cs
+++ b/src/Ryujinx.HLE/HOS/Services/Mii/Types/Ver3StoreData.cs
@@ -1,4 +1,6 @@
-using System;
+using Ryujinx.Common.Memory;
+using Ryujinx.Common.Utilities;
+using System;
 using System.Runtime.InteropServices;
 
 namespace Ryujinx.HLE.HOS.Services.Mii.Types
@@ -8,9 +10,9 @@ namespace Ryujinx.HLE.HOS.Services.Mii.Types
     {
         public const int Size = 0x60;
 
-        private byte _storage;
+        private Array96<byte> _storage;
 
-        public Span<byte> Storage => MemoryMarshal.CreateSpan(ref _storage, Size);
+        public Span<byte> Storage => _storage.AsSpan();
 
         // TODO: define all getters/setters
     }