mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Update struct layout of most remaining Fs structs
This commit is contained in:
parent
9a358a4e30
commit
b7e8ea8249
12 changed files with 272 additions and 112 deletions
32
src/LibHac/Common/FixedArrays/Array28.cs
Normal file
32
src/LibHac/Common/FixedArrays/Array28.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma warning disable CS0169, IDE0051 // Remove unused private members
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Common.FixedArrays;
|
||||
|
||||
public struct Array28<T>
|
||||
{
|
||||
public const int Length = 28;
|
||||
|
||||
private Array16<T> _0;
|
||||
private Array8<T> _16;
|
||||
private Array4<T> _24;
|
||||
|
||||
public ref T this[int i] => ref Items[i];
|
||||
|
||||
public Span<T> Items
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length);
|
||||
}
|
||||
|
||||
public readonly ReadOnlySpan<T> ItemsRo
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator ReadOnlySpan<T>(in Array28<T> value) => value.ItemsRo;
|
||||
}
|
31
src/LibHac/Common/FixedArrays/Array38.cs
Normal file
31
src/LibHac/Common/FixedArrays/Array38.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma warning disable CS0169, IDE0051 // Remove unused private members
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibHac.Common.FixedArrays;
|
||||
|
||||
public struct Array38<T>
|
||||
{
|
||||
public const int Length = 38;
|
||||
|
||||
private Array32<T> _0;
|
||||
private Array6<T> _32;
|
||||
|
||||
public ref T this[int i] => ref Items[i];
|
||||
|
||||
public Span<T> Items
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length);
|
||||
}
|
||||
|
||||
public readonly ReadOnlySpan<T> ItemsRo
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static implicit operator ReadOnlySpan<T>(in Array38<T> value) => value.ItemsRo;
|
||||
}
|
|
@ -1,53 +1,27 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
|
||||
namespace LibHac.Fs.Impl;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
|
||||
public struct InitialDataAad
|
||||
{
|
||||
public byte this[int i]
|
||||
{
|
||||
readonly get => BytesRo[i];
|
||||
set => Bytes[i] = value;
|
||||
public Array32<byte> Value;
|
||||
}
|
||||
|
||||
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
|
||||
public readonly ReadOnlySpan<byte> BytesRo => SpanHelpers.AsReadOnlyByteSpan(in this);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct KeySeed
|
||||
{
|
||||
public byte this[int i]
|
||||
{
|
||||
readonly get => BytesRo[i];
|
||||
set => Bytes[i] = value;
|
||||
public Array16<byte> Value;
|
||||
}
|
||||
|
||||
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
|
||||
public readonly ReadOnlySpan<byte> BytesRo => SpanHelpers.AsReadOnlyByteSpan(in this);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct InitialDataMac
|
||||
{
|
||||
public byte this[int i]
|
||||
{
|
||||
readonly get => BytesRo[i];
|
||||
set => Bytes[i] = value;
|
||||
public Array16<byte> Value;
|
||||
}
|
||||
|
||||
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
|
||||
public readonly ReadOnlySpan<byte> BytesRo => SpanHelpers.AsReadOnlyByteSpan(in this);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x20)]
|
||||
public struct ImportReportInfo
|
||||
{
|
||||
public byte DiffChunkCount;
|
||||
public byte DoubleDivisionDiffChunkCount;
|
||||
public byte HalfDivisionDiffChunkCount;
|
||||
public byte CompressionRate;
|
||||
public Array28<byte> Reserved;
|
||||
}
|
|
@ -1,32 +1,13 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
|
||||
namespace LibHac.Fs;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x100)]
|
||||
public struct RsaEncryptedKey
|
||||
{
|
||||
public byte this[int i]
|
||||
{
|
||||
readonly get => BytesRo[i];
|
||||
set => Bytes[i] = value;
|
||||
public Array256<byte> Value;
|
||||
}
|
||||
|
||||
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
|
||||
public readonly ReadOnlySpan<byte> BytesRo => SpanHelpers.AsReadOnlyByteSpan(in this);
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public struct AesKey
|
||||
{
|
||||
public byte this[int i]
|
||||
{
|
||||
readonly get => BytesRo[i];
|
||||
set => Bytes[i] = value;
|
||||
}
|
||||
|
||||
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
|
||||
public readonly ReadOnlySpan<byte> BytesRo => SpanHelpers.AsReadOnlyByteSpan(in this);
|
||||
public Array16<byte> Value;
|
||||
}
|
|
@ -752,30 +752,30 @@ public readonly struct AccessControlBits
|
|||
public bool CanWriteSaveDataFileSystemExtraDataTimeStamp() => Has(Bits.SaveDataBackUp);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x2C)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
internal struct AccessControlDescriptor
|
||||
{
|
||||
[FieldOffset(0x00)] public byte Version;
|
||||
[FieldOffset(0x01)] public byte ContentOwnerIdCount;
|
||||
[FieldOffset(0x02)] public byte SaveDataOwnerIdCount;
|
||||
[FieldOffset(0x04)] public ulong AccessFlags;
|
||||
[FieldOffset(0x0C)] public ulong ContentOwnerIdMin;
|
||||
[FieldOffset(0x14)] public ulong ContentOwnerIdMax;
|
||||
[FieldOffset(0x1C)] public ulong SaveDataOwnerIdMin;
|
||||
[FieldOffset(0x24)] public ulong SaveDataOwnerIdMax;
|
||||
public byte Version;
|
||||
public byte ContentOwnerIdCount;
|
||||
public byte SaveDataOwnerIdCount;
|
||||
public ulong AccessFlags;
|
||||
public ulong ContentOwnerIdMin;
|
||||
public ulong ContentOwnerIdMax;
|
||||
public ulong SaveDataOwnerIdMin;
|
||||
public ulong SaveDataOwnerIdMax;
|
||||
// public ulong ContentOwnerIds[ContentOwnerIdCount];
|
||||
// public ulong SaveDataOwnerIds[SaveDataOwnerIdCount];
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x1C)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
internal struct AccessControlDataHeader
|
||||
{
|
||||
[FieldOffset(0x00)] public byte Version;
|
||||
[FieldOffset(0x04)] public ulong AccessFlags;
|
||||
[FieldOffset(0x0C)] public int ContentOwnerInfoOffset;
|
||||
[FieldOffset(0x10)] public int ContentOwnerInfoSize;
|
||||
[FieldOffset(0x14)] public int SaveDataOwnerInfoOffset;
|
||||
[FieldOffset(0x18)] public int SaveDataOwnerInfoSize;
|
||||
public byte Version;
|
||||
public ulong AccessFlags;
|
||||
public int ContentOwnerInfoOffset;
|
||||
public int ContentOwnerInfoSize;
|
||||
public int SaveDataOwnerInfoOffset;
|
||||
public int SaveDataOwnerInfoSize;
|
||||
|
||||
// [FieldOffset(ContentOwnerInfoOffset)]
|
||||
// public int ContentOwnerInfoCount;
|
||||
|
|
|
@ -498,13 +498,12 @@ internal class MultiCommitManager : IMultiCommitManager
|
|||
return Recover(multiCommitInterface, fileSystem.Get, saveService);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x18)]
|
||||
private struct Context
|
||||
{
|
||||
[FieldOffset(0x00)] public int Version;
|
||||
[FieldOffset(0x04)] public CommitState State;
|
||||
[FieldOffset(0x08)] public int FileSystemCount;
|
||||
[FieldOffset(0x10)] public long Counter;
|
||||
public int Version;
|
||||
public CommitState State;
|
||||
public int FileSystemCount;
|
||||
public long Counter;
|
||||
}
|
||||
|
||||
private enum CommitState
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Fs;
|
||||
|
||||
namespace LibHac.FsSrv;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
|
||||
public struct SaveDataIndexerValue
|
||||
{
|
||||
[FieldOffset(0x00)] public ulong SaveDataId;
|
||||
[FieldOffset(0x08)] public long Size;
|
||||
[FieldOffset(0x10)] public ulong Field10;
|
||||
[FieldOffset(0x18)] public SaveDataSpaceId SpaceId;
|
||||
[FieldOffset(0x19)] public SaveDataState State;
|
||||
public ulong SaveDataId;
|
||||
public long Size;
|
||||
public ulong Field10;
|
||||
public SaveDataSpaceId SpaceId;
|
||||
public SaveDataState State;
|
||||
public Array38<byte> Reserved;
|
||||
}
|
|
@ -1,26 +1,21 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Common.FixedArrays;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Util;
|
||||
|
||||
namespace LibHac.FsSrv.Sf;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = MaxLength + 1)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public readonly struct FspPath
|
||||
{
|
||||
internal const int MaxLength = 0x300;
|
||||
|
||||
#if DEBUG
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding000;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding100;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding200;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte Padding300;
|
||||
#endif
|
||||
private readonly Array769<byte> _value;
|
||||
|
||||
public ReadOnlySpan<byte> Str => SpanHelpers.AsReadOnlyByteSpan(in this);
|
||||
public ReadOnlySpan<byte> Str => SpanHelpers.AsReadOnlyByteSpan(in _value);
|
||||
|
||||
public static Result FromSpan(out FspPath fspPath, ReadOnlySpan<byte> path)
|
||||
{
|
||||
|
@ -28,7 +23,7 @@ public readonly struct FspPath
|
|||
|
||||
Span<byte> str = SpanHelpers.AsByteSpan(ref fspPath);
|
||||
|
||||
// Ensure null terminator even if the creation fails for safety
|
||||
// Ensure null terminator even if the creation fails
|
||||
str[MaxLength] = 0;
|
||||
|
||||
var sb = new U8StringBuilder(str);
|
||||
|
|
|
@ -1,23 +1,14 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
|
||||
#if DEBUG
|
||||
using System.Diagnostics;
|
||||
#endif
|
||||
using LibHac.Common.FixedArrays;
|
||||
|
||||
namespace LibHac.FsSrv.Sf;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = PathTool.EntryNameLengthMax + 1)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public readonly struct Path
|
||||
{
|
||||
#if DEBUG
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding000;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding100;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding200;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte Padding300;
|
||||
#endif
|
||||
private readonly Array769<byte> _value;
|
||||
|
||||
public ReadOnlySpan<byte> Str => SpanHelpers.AsReadOnlyByteSpan(in this);
|
||||
public ReadOnlySpan<byte> Str => SpanHelpers.AsReadOnlyByteSpan(in _value);
|
||||
}
|
|
@ -1,18 +1,19 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using LibHac.Common.FixedArrays;
|
||||
|
||||
namespace LibHac.FsSrv.Storage;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
public readonly struct StorageDeviceHandle : IEquatable<StorageDeviceHandle>
|
||||
{
|
||||
public readonly uint Value;
|
||||
public readonly StorageDevicePortId PortId;
|
||||
public readonly Array11<byte> Reserved;
|
||||
|
||||
public StorageDeviceHandle(uint value, StorageDevicePortId portId)
|
||||
{
|
||||
Value = value;
|
||||
PortId = portId;
|
||||
Reserved = default;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj) => obj is StorageDeviceHandle other && Equals(other);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Impl;
|
||||
using Xunit;
|
||||
using static LibHac.Tests.Common.Layout;
|
||||
|
||||
|
@ -289,4 +290,68 @@ public class TypeLayoutTests
|
|||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void RsaEncryptedKey_Layout()
|
||||
{
|
||||
var s = new RsaEncryptedKey();
|
||||
|
||||
Assert.Equal(0x100, Unsafe.SizeOf<RsaEncryptedKey>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AesKey_Layout()
|
||||
{
|
||||
var s = new AesKey();
|
||||
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<AesKey>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void InitialDataAad_Layout()
|
||||
{
|
||||
var s = new InitialDataAad();
|
||||
|
||||
Assert.Equal(0x20, Unsafe.SizeOf<InitialDataAad>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void KeySeed_Layout()
|
||||
{
|
||||
var s = new KeySeed();
|
||||
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<KeySeed>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void InitialDataMac_Layout()
|
||||
{
|
||||
var s = new InitialDataMac();
|
||||
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<InitialDataMac>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void ImportReportInfo_Layout()
|
||||
{
|
||||
var s = new ImportReportInfo();
|
||||
|
||||
Assert.Equal(0x20, Unsafe.SizeOf<ImportReportInfo>());
|
||||
|
||||
Assert.Equal(0, GetOffset(in s, in s.DiffChunkCount));
|
||||
Assert.Equal(1, GetOffset(in s, in s.DoubleDivisionDiffChunkCount));
|
||||
Assert.Equal(2, GetOffset(in s, in s.HalfDivisionDiffChunkCount));
|
||||
Assert.Equal(3, GetOffset(in s, in s.CompressionRate));
|
||||
Assert.Equal(4, GetOffset(in s, in s.Reserved));
|
||||
}
|
||||
}
|
91
tests/LibHac.Tests/FsSrv/TypeLayoutTests.cs
Normal file
91
tests/LibHac.Tests/FsSrv/TypeLayoutTests.cs
Normal file
|
@ -0,0 +1,91 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using LibHac.FsSrv;
|
||||
using LibHac.FsSrv.Impl;
|
||||
using LibHac.FsSrv.Sf;
|
||||
using LibHac.FsSrv.Storage;
|
||||
using Xunit;
|
||||
using static LibHac.Tests.Common.Layout;
|
||||
|
||||
namespace LibHac.Tests.FsSrv;
|
||||
|
||||
public class TypeLayoutTests
|
||||
{
|
||||
[Fact]
|
||||
public static void AccessControlDescriptor_Layout()
|
||||
{
|
||||
var s = new AccessControlDescriptor();
|
||||
|
||||
Assert.Equal(0x2C, Unsafe.SizeOf<AccessControlDescriptor>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Version));
|
||||
Assert.Equal(0x01, GetOffset(in s, in s.ContentOwnerIdCount));
|
||||
Assert.Equal(0x02, GetOffset(in s, in s.SaveDataOwnerIdCount));
|
||||
Assert.Equal(0x04, GetOffset(in s, in s.AccessFlags));
|
||||
Assert.Equal(0x0C, GetOffset(in s, in s.ContentOwnerIdMin));
|
||||
Assert.Equal(0x14, GetOffset(in s, in s.ContentOwnerIdMax));
|
||||
Assert.Equal(0x1C, GetOffset(in s, in s.SaveDataOwnerIdMin));
|
||||
Assert.Equal(0x24, GetOffset(in s, in s.SaveDataOwnerIdMax));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AccessControlDataHeader_Layout()
|
||||
{
|
||||
var s = new AccessControlDataHeader();
|
||||
|
||||
Assert.Equal(0x1C, Unsafe.SizeOf<AccessControlDataHeader>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Version));
|
||||
Assert.Equal(0x04, GetOffset(in s, in s.AccessFlags));
|
||||
Assert.Equal(0x0C, GetOffset(in s, in s.ContentOwnerInfoOffset));
|
||||
Assert.Equal(0x10, GetOffset(in s, in s.ContentOwnerInfoSize));
|
||||
Assert.Equal(0x14, GetOffset(in s, in s.SaveDataOwnerInfoOffset));
|
||||
Assert.Equal(0x18, GetOffset(in s, in s.SaveDataOwnerInfoSize));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void FspPath_Layout()
|
||||
{
|
||||
var s = new FspPath();
|
||||
|
||||
Assert.Equal(0x301, Unsafe.SizeOf<FspPath>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Str[0]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Path_Layout()
|
||||
{
|
||||
var s = new Path();
|
||||
|
||||
Assert.Equal(0x301, Unsafe.SizeOf<Path>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.Str[0]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void StorageDeviceHandle_Layout()
|
||||
{
|
||||
var s = new StorageDeviceHandle();
|
||||
|
||||
Assert.Equal(0x10, Unsafe.SizeOf<StorageDeviceHandle>());
|
||||
|
||||
Assert.Equal(0x0, GetOffset(in s, in s.Value));
|
||||
Assert.Equal(0x4, GetOffset(in s, in s.PortId));
|
||||
Assert.Equal(0x5, GetOffset(in s, in s.Reserved));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void SaveDataIndexerValue_Layout()
|
||||
{
|
||||
var s = new SaveDataIndexerValue();
|
||||
|
||||
Assert.Equal(0x40, Unsafe.SizeOf<SaveDataIndexerValue>());
|
||||
|
||||
Assert.Equal(0x00, GetOffset(in s, in s.SaveDataId));
|
||||
Assert.Equal(0x08, GetOffset(in s, in s.Size));
|
||||
Assert.Equal(0x10, GetOffset(in s, in s.Field10));
|
||||
Assert.Equal(0x18, GetOffset(in s, in s.SpaceId));
|
||||
Assert.Equal(0x19, GetOffset(in s, in s.State));
|
||||
Assert.Equal(0x1A, GetOffset(in s, in s.Reserved));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue