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 65956ed32..807bd69c3 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 d9bcecee1..5041dc882 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 00e49ecb9..4f6e289e2 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 dc21d8e56..6665ca6d4 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 994f6b7ce..178b48318 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 70bb348b5..1c7db8e66 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
     }