Reduce usage of Marshal.PtrToStructure and Marshal.StructureToPtr (#3805)
* common: Make BinaryReaderExtensions Read & Write take unamanged types This allows us to not rely on Marshal.PtrToStructure and Marshal.StructureToPtr for those. * common: Make MemoryHelper Read & Write takes unamanged types * Update Marshal.SizeOf => Unsafe.SizeOf when appropriate and start moving software applet to unmanaged types
This commit is contained in:
parent
a1ddaa2736
commit
f4e879a1e6
16 changed files with 88 additions and 137 deletions
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Common
|
namespace Ryujinx.Common
|
||||||
|
@ -7,49 +8,15 @@ namespace Ryujinx.Common
|
||||||
public static class BinaryReaderExtensions
|
public static class BinaryReaderExtensions
|
||||||
{
|
{
|
||||||
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
||||||
where T : struct
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
int size = Marshal.SizeOf<T>();
|
return MemoryMarshal.Cast<byte, T>(reader.ReadBytes(Unsafe.SizeOf<T>()))[0];
|
||||||
|
|
||||||
byte[] data = reader.ReadBytes(size);
|
|
||||||
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe static T[] ReadStructArray<T>(this BinaryReader reader, int count)
|
|
||||||
where T : struct
|
|
||||||
{
|
|
||||||
int size = Marshal.SizeOf<T>();
|
|
||||||
|
|
||||||
T[] result = new T[count];
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
byte[] data = reader.ReadBytes(size);
|
|
||||||
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
result[i] = Marshal.PtrToStructure<T>((IntPtr)ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
||||||
where T : struct
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
long size = Marshal.SizeOf<T>();
|
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.Write(data);
|
writer.Write(data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -23,34 +24,18 @@ namespace Ryujinx.Cpu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : struct
|
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : unmanaged
|
||||||
{
|
{
|
||||||
long size = Marshal.SizeOf<T>();
|
return MemoryMarshal.Cast<byte, T>(memory.GetSpan(position, Unsafe.SizeOf<T>()))[0];
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
|
|
||||||
memory.Read(position, data);
|
|
||||||
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : struct
|
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : unmanaged
|
||||||
{
|
{
|
||||||
long size = Marshal.SizeOf<T>();
|
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||||
|
|
||||||
byte[] data = new byte[size];
|
|
||||||
|
|
||||||
fixed (byte* ptr = data)
|
|
||||||
{
|
|
||||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
memory.Write(position, data);
|
memory.Write(position, data);
|
||||||
|
|
||||||
return (ulong)size;
|
return (ulong)data.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ReadAsciiString(IVirtualMemoryManager memory, ulong position, long maxSize = -1)
|
public static string ReadAsciiString(IVirtualMemoryManager memory, ulong position, long maxSize = -1)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||||
|
@ -9,6 +10,7 @@ using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -78,13 +80,13 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||||
var launchParams = _normalSession.Pop();
|
var launchParams = _normalSession.Pop();
|
||||||
var keyboardConfig = _normalSession.Pop();
|
var keyboardConfig = _normalSession.Pop();
|
||||||
|
|
||||||
_isBackground = keyboardConfig.Length == Marshal.SizeOf<SoftwareKeyboardInitialize>();
|
_isBackground = keyboardConfig.Length == Unsafe.SizeOf<SoftwareKeyboardInitialize>();
|
||||||
|
|
||||||
if (_isBackground)
|
if (_isBackground)
|
||||||
{
|
{
|
||||||
// Initialize the keyboard applet in background mode.
|
// Initialize the keyboard applet in background mode.
|
||||||
|
|
||||||
_keyboardBackgroundInitialize = ReadStruct<SoftwareKeyboardInitialize>(keyboardConfig);
|
_keyboardBackgroundInitialize = MemoryMarshal.Read<SoftwareKeyboardInitialize>(keyboardConfig);
|
||||||
_backgroundState = InlineKeyboardState.Uninitialized;
|
_backgroundState = InlineKeyboardState.Uninitialized;
|
||||||
|
|
||||||
if (_device.UiHandler == null)
|
if (_device.UiHandler == null)
|
||||||
|
@ -342,7 +344,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int wordsCount = reader.ReadInt32();
|
int wordsCount = reader.ReadInt32();
|
||||||
int wordSize = Marshal.SizeOf<SoftwareKeyboardUserWord>();
|
int wordSize = Unsafe.SizeOf<SoftwareKeyboardUserWord>();
|
||||||
remaining = stream.Length - stream.Position;
|
remaining = stream.Length - stream.Position;
|
||||||
|
|
||||||
if (wordsCount > MaxUserWords)
|
if (wordsCount > MaxUserWords)
|
||||||
|
@ -359,8 +361,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||||
|
|
||||||
for (int word = 0; word < wordsCount; word++)
|
for (int word = 0; word < wordsCount; word++)
|
||||||
{
|
{
|
||||||
byte[] wordData = reader.ReadBytes(wordSize);
|
_keyboardBackgroundUserWords[word] = reader.ReadStruct<SoftwareKeyboardUserWord>();
|
||||||
_keyboardBackgroundUserWords[word] = ReadStruct<SoftwareKeyboardUserWord>(wordData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -369,27 +370,25 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||||
case InlineKeyboardRequest.SetCustomizeDic:
|
case InlineKeyboardRequest.SetCustomizeDic:
|
||||||
// Read the custom dic data.
|
// Read the custom dic data.
|
||||||
remaining = stream.Length - stream.Position;
|
remaining = stream.Length - stream.Position;
|
||||||
if (remaining != Marshal.SizeOf<SoftwareKeyboardCustomizeDic>())
|
if (remaining != Unsafe.SizeOf<SoftwareKeyboardCustomizeDic>())
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Customize Dic of {remaining} bytes");
|
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Customize Dic of {remaining} bytes");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var keyboardDicData = reader.ReadBytes((int)remaining);
|
_keyboardBackgroundDic = reader.ReadStruct<SoftwareKeyboardCustomizeDic>();
|
||||||
_keyboardBackgroundDic = ReadStruct<SoftwareKeyboardCustomizeDic>(keyboardDicData);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InlineKeyboardRequest.SetCustomizedDictionaries:
|
case InlineKeyboardRequest.SetCustomizedDictionaries:
|
||||||
// Read the custom dictionaries data.
|
// Read the custom dictionaries data.
|
||||||
remaining = stream.Length - stream.Position;
|
remaining = stream.Length - stream.Position;
|
||||||
if (remaining != Marshal.SizeOf<SoftwareKeyboardDictSet>())
|
if (remaining != Unsafe.SizeOf<SoftwareKeyboardDictSet>())
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard DictSet of {remaining} bytes");
|
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard DictSet of {remaining} bytes");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var keyboardDictData = reader.ReadBytes((int)remaining);
|
_keyboardBackgroundDictSet = reader.ReadStruct<SoftwareKeyboardDictSet>();
|
||||||
_keyboardBackgroundDictSet = ReadStruct<SoftwareKeyboardDictSet>(keyboardDictData);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InlineKeyboardRequest.Calc:
|
case InlineKeyboardRequest.Calc:
|
||||||
|
|
|
@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A structure used by SetCustomizeDic request to software keyboard.
|
/// A structure used by SetCustomizeDic request to software keyboard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
[StructLayout(LayoutKind.Sequential, Size = 0x70)]
|
||||||
struct SoftwareKeyboardCustomizeDic
|
struct SoftwareKeyboardCustomizeDic
|
||||||
{
|
{
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)]
|
// Unknown
|
||||||
public byte[] Unknown;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
{
|
{
|
||||||
|
@ -21,8 +22,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Array of word entries in the buffer.
|
/// Array of word entries in the buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
public Array24<ulong> Entries;
|
||||||
public ulong[] Entries;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of used entries in the Entries field.
|
/// Number of used entries in the Entries field.
|
||||||
|
|
|
@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A structure used by SetUserWordInfo request to the software keyboard.
|
/// A structure used by SetUserWordInfo request to the software keyboard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
[StructLayout(LayoutKind.Sequential, Size = 0x64)]
|
||||||
struct SoftwareKeyboardUserWord
|
struct SoftwareKeyboardUserWord
|
||||||
{
|
{
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
|
// Unknown
|
||||||
public byte[] Unknown;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)]
|
[StructLayout(LayoutKind.Sequential, Pack = 0x8)]
|
||||||
struct UserPresence
|
struct UserPresence
|
||||||
{
|
{
|
||||||
public UserId UserId;
|
public UserId UserId;
|
||||||
|
@ -13,15 +16,20 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||||
[MarshalAs(UnmanagedType.I1)]
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
public bool SamePresenceGroupApplication;
|
public bool SamePresenceGroupApplication;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)]
|
public Array3<byte> Unknown;
|
||||||
public char[] Unknown;
|
private AppKeyValueStorageHolder _appKeyValueStorage;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xC0)]
|
public Span<byte> AppKeyValueStorage => MemoryMarshal.Cast<AppKeyValueStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _appKeyValueStorage, AppKeyValueStorageHolder.Size));
|
||||||
public char[] AppKeyValueStorage;
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = Size)]
|
||||||
|
private struct AppKeyValueStorageHolder
|
||||||
|
{
|
||||||
|
public const int Size = 0xC0;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {AppKeyValueStorage} }}";
|
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {Encoding.ASCII.GetString(AppKeyValueStorage)} }}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -236,23 +236,14 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||||
ulong position = context.Request.PtrBuff[0].Position;
|
ulong position = context.Request.PtrBuff[0].Position;
|
||||||
ulong size = context.Request.PtrBuff[0].Size;
|
ulong size = context.Request.PtrBuff[0].Size;
|
||||||
|
|
||||||
byte[] bufferContent = new byte[size];
|
ReadOnlySpan<UserPresence> userPresenceInputArray = MemoryMarshal.Cast<byte, UserPresence>(context.Memory.GetSpan(position, (int)size));
|
||||||
|
|
||||||
context.Memory.Read(position, bufferContent);
|
|
||||||
|
|
||||||
if (uuid.IsNull)
|
if (uuid.IsNull)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|
||||||
int elementCount = bufferContent.Length / Marshal.SizeOf<UserPresence>();
|
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray = userPresenceInputArray.ToArray() });
|
||||||
|
|
||||||
using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(bufferContent)))
|
|
||||||
{
|
|
||||||
UserPresence[] userPresenceInputArray = bufferReader.ReadStructArray<UserPresence>(elementCount);
|
|
||||||
|
|
||||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray });
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x10)]
|
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||||
struct NotificationInfo
|
struct NotificationInfo
|
||||||
{
|
{
|
||||||
public NotificationEventType Type;
|
public NotificationEventType Type;
|
||||||
|
private Array4<byte> _padding;
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4)]
|
|
||||||
public char[] Padding;
|
|
||||||
|
|
||||||
public long NetworkUserIdPlaceholder;
|
public long NetworkUserIdPlaceholder;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||||
|
@ -75,7 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||||
|
|
||||||
for (int i = 0; i < filteredApplicationPlayStatistics.Count(); i++)
|
for (int i = 0; i < filteredApplicationPlayStatistics.Count(); i++)
|
||||||
{
|
{
|
||||||
MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Marshal.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
|
MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Unsafe.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
context.ResponseData.Write(filteredApplicationPlayStatistics.Count());
|
context.ResponseData.Write(filteredApplicationPlayStatistics.Count());
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
|
@ -16,14 +17,22 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||||
public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
|
public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
|
||||||
public SteadyClockTimePoint SteadyClockTimePoint;
|
public SteadyClockTimePoint SteadyClockTimePoint;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)]
|
private LocationNameStorageHolder _locationName;
|
||||||
public char[] LocationName;
|
|
||||||
|
public Span<byte> LocationName => MemoryMarshal.Cast<LocationNameStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _locationName, LocationNameStorageHolder.Size));
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.I1)]
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
public bool IsAutomaticCorrectionEnabled;
|
public bool IsAutomaticCorrectionEnabled;
|
||||||
public byte Type;
|
public byte Type;
|
||||||
public ushort Unknown;
|
public ushort Unknown;
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = Size)]
|
||||||
|
private struct LocationNameStorageHolder
|
||||||
|
{
|
||||||
|
public const int Size = 0x24;
|
||||||
|
}
|
||||||
|
|
||||||
public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
|
public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
|
||||||
{
|
{
|
||||||
currentTime = 0;
|
currentTime = 0;
|
||||||
|
|
|
@ -8,7 +8,9 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Time
|
namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
{
|
{
|
||||||
|
@ -281,7 +283,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
{
|
{
|
||||||
byte type = context.RequestData.ReadByte();
|
byte type = context.RequestData.ReadByte();
|
||||||
|
|
||||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ClockSnapshot>());
|
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Unsafe.SizeOf<ClockSnapshot>());
|
||||||
|
|
||||||
context.RequestData.BaseStream.Position += 7;
|
context.RequestData.BaseStream.Position += 7;
|
||||||
|
|
||||||
|
@ -372,12 +374,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] tzName = deviceLocationName.ToCharArray();
|
ReadOnlySpan<byte> tzName = Encoding.ASCII.GetBytes(deviceLocationName);
|
||||||
char[] locationName = new char[0x24];
|
|
||||||
|
|
||||||
Array.Copy(tzName, locationName, tzName.Length);
|
tzName.CopyTo(clockSnapshot.LocationName);
|
||||||
|
|
||||||
clockSnapshot.LocationName = locationName;
|
|
||||||
|
|
||||||
result = ClockSnapshot.GetCurrentTime(out clockSnapshot.UserTime, currentTimePoint, clockSnapshot.UserContext);
|
result = ClockSnapshot.GetCurrentTime(out clockSnapshot.UserTime, currentTimePoint, clockSnapshot.UserContext);
|
||||||
|
|
||||||
|
@ -414,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||||
|
|
||||||
private ClockSnapshot ReadClockSnapshotFromBuffer(ServiceCtx context, IpcPtrBuffDesc ipcDesc)
|
private ClockSnapshot ReadClockSnapshotFromBuffer(ServiceCtx context, IpcPtrBuffDesc ipcDesc)
|
||||||
{
|
{
|
||||||
Debug.Assert(ipcDesc.Size == (ulong)Marshal.SizeOf<ClockSnapshot>());
|
Debug.Assert(ipcDesc.Size == (ulong)Unsafe.SizeOf<ClockSnapshot>());
|
||||||
|
|
||||||
byte[] temp = new byte[ipcDesc.Size];
|
byte[] temp = new byte[ipcDesc.Size];
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ using Ryujinx.HLE.Utilities;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
@ -890,14 +891,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
||||||
|
|
||||||
long streamLength = reader.BaseStream.Length;
|
long streamLength = reader.BaseStream.Length;
|
||||||
|
|
||||||
if (streamLength < Marshal.SizeOf<TzifHeader>())
|
if (streamLength < Unsafe.SizeOf<TzifHeader>())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TzifHeader header = reader.ReadStruct<TzifHeader>();
|
TzifHeader header = reader.ReadStruct<TzifHeader>();
|
||||||
|
|
||||||
streamLength -= Marshal.SizeOf<TzifHeader>();
|
streamLength -= Unsafe.SizeOf<TzifHeader>();
|
||||||
|
|
||||||
int ttisGMTCount = Detzcode32(header.TtisGMTCount);
|
int ttisGMTCount = Detzcode32(header.TtisGMTCount);
|
||||||
int ttisSTDCount = Detzcode32(header.TtisSTDCount);
|
int ttisSTDCount = Detzcode32(header.TtisSTDCount);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
{
|
{
|
||||||
|
@ -8,9 +9,7 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
public MessageType Type;
|
public MessageType Type;
|
||||||
public SubscriberType SubscriberType;
|
public SubscriberType SubscriberType;
|
||||||
public byte Slot;
|
public byte Slot;
|
||||||
|
public Array6<byte> MacAddress;
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
||||||
public byte[] MacAddress;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
@ -27,11 +26,8 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
public uint DPadAnalog;
|
public uint DPadAnalog;
|
||||||
public ulong MainButtonsAnalog;
|
public ulong MainButtonsAnalog;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
public Array6<byte> Touch1;
|
||||||
public byte[] Touch1;
|
public Array6<byte> Touch2;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
|
||||||
public byte[] Touch2;
|
|
||||||
|
|
||||||
public ulong MotionTimestamp;
|
public ulong MotionTimestamp;
|
||||||
public float AccelerometerX;
|
public float AccelerometerX;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
{
|
{
|
||||||
|
@ -14,8 +15,6 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
{
|
{
|
||||||
public MessageType Type;
|
public MessageType Type;
|
||||||
public int PortsCount;
|
public int PortsCount;
|
||||||
|
public Array4<byte> PortIndices;
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
|
||||||
public byte[] PortIndices;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Runtime.InteropServices;
|
using Ryujinx.Common.Memory;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
{
|
{
|
||||||
|
@ -11,8 +12,7 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||||
public DeviceModelType ModelType;
|
public DeviceModelType ModelType;
|
||||||
public ConnectionType ConnectionType;
|
public ConnectionType ConnectionType;
|
||||||
|
|
||||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
public Array6<byte> MacAddress;
|
||||||
public byte[] MacAddress;
|
|
||||||
public BatteryStatus BatteryStatus;
|
public BatteryStatus BatteryStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue