Update layout of Arp, Bcat, and some Fs structs

Stop using LayoutKind.Explicit and the Size parameter of StructLayout
This commit is contained in:
Alex Barney 2021-12-29 15:47:20 -07:00
parent 5380902376
commit 57750b896d
22 changed files with 525 additions and 158 deletions

View File

@ -1,12 +1,16 @@
using System.Runtime.InteropServices;
namespace LibHac.Arp;
namespace LibHac.Arp;
[StructLayout(LayoutKind.Explicit, Size = 0x10)]
public struct ApplicationLaunchProperty
{
[FieldOffset(0x0)] public ApplicationId ApplicationId;
[FieldOffset(0x8)] public uint Version;
[FieldOffset(0xC)] public Ncm.StorageId BaseStorageId;
[FieldOffset(0xD)] public Ncm.StorageId UpdateStorageId;
public ApplicationId ApplicationId;
public uint Version;
public Ncm.StorageId StorageId;
public Ncm.StorageId PatchStorageId;
public ApplicationKind ApplicationKind;
}
public enum ApplicationKind : byte
{
Application = 0,
MicroApplication = 1
}

View File

@ -1,15 +1,12 @@
using System.Runtime.InteropServices;
namespace LibHac.Bcat;
namespace LibHac.Bcat;
[StructLayout(LayoutKind.Explicit, Size = 0x38)]
public struct DeliveryCacheDirectoryEntry
{
[FieldOffset(0x00)] public FileName Name;
[FieldOffset(0x20)] public long Size;
[FieldOffset(0x28)] public Digest Digest;
public FileName Name;
public long Size;
public Digest Digest;
public DeliveryCacheDirectoryEntry(ref FileName name, long size, ref Digest digest)
public DeliveryCacheDirectoryEntry(in FileName name, long size, in Digest digest)
{
Name = name;
Size = size;

View File

@ -1,28 +1,16 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
using System.Diagnostics;
using LibHac.Common.FixedArrays;
using LibHac.Util;
namespace LibHac.Bcat;
[DebuggerDisplay("{ToString()}")]
[StructLayout(LayoutKind.Sequential, Size = 16)]
public struct Digest
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
public Array16<byte> Value;
public byte this[int i]
public readonly override string ToString()
{
get => Bytes[i];
set => Bytes[i] = value;
}
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
public override string ToString()
{
return Bytes.ToHexString();
return Value.ItemsRo.ToHexString();
}
}

View File

@ -1,33 +1,20 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Common.FixedArrays;
using LibHac.Util;
namespace LibHac.Bcat;
[DebuggerDisplay("{ToString()}")]
[StructLayout(LayoutKind.Sequential, Size = MaxSize)]
public struct DirectoryName
{
private const int MaxSize = 0x20;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy2;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy3;
public Array32<byte> Value;
public byte this[int i]
public readonly bool IsValid()
{
get => Bytes[i];
set => Bytes[i] = value;
}
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
public bool IsValid()
{
Span<byte> name = Bytes;
ReadOnlySpan<byte> name = Value.ItemsRo;
int i;
for (i = 0; i < name.Length; i++)
@ -45,8 +32,8 @@ public struct DirectoryName
return name[i] == 0;
}
public override string ToString()
public readonly override string ToString()
{
return StringUtils.Utf8ZToString(Bytes);
return StringUtils.Utf8ZToString(Value.ItemsRo);
}
}

View File

@ -1,33 +1,20 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Common.FixedArrays;
using LibHac.Util;
namespace LibHac.Bcat;
[DebuggerDisplay("{ToString()}")]
[StructLayout(LayoutKind.Sequential, Size = MaxSize)]
public struct FileName
{
private const int MaxSize = 0x20;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy2;
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy3;
public Array32<byte> Value;
public byte this[int i]
public readonly bool IsValid()
{
get => Bytes[i];
set => Bytes[i] = value;
}
public Span<byte> Bytes => SpanHelpers.AsByteSpan(ref this);
public bool IsValid()
{
Span<byte> name = Bytes;
ReadOnlySpan<byte> name = Value.ItemsRo;
int i;
for (i = 0; i < name.Length; i++)
@ -48,8 +35,8 @@ public struct FileName
return name[i - 1] != '.';
}
public override string ToString()
public readonly override string ToString()
{
return StringUtils.Utf8ZToString(Bytes);
return StringUtils.Utf8ZToString(Value.ItemsRo);
}
}

View File

@ -1,10 +1,10 @@
using System.Runtime.InteropServices;
using LibHac.Common.FixedArrays;
namespace LibHac.Bcat.Impl.Service.Core;
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
internal struct DeliveryCacheDirectoryMetaEntry
{
[FieldOffset(0x00)] public DirectoryName Name;
[FieldOffset(0x20)] public Digest Digest;
public DirectoryName Name;
public Digest Digest;
public Array16<byte> Reserved;
}

View File

@ -56,7 +56,7 @@ internal class DeliveryCacheFileMetaAccessor
{
for (int i = 0; i < Count; i++)
{
if (StringUtils.CompareCaseInsensitive(Entries[i].Name.Bytes, fileName.Bytes) == 0)
if (StringUtils.CompareCaseInsensitive(Entries[i].Name.Value, fileName.Value) == 0)
{
entry = Entries[i];
return Result.Success;

View File

@ -1,12 +1,12 @@
using System.Runtime.InteropServices;
using LibHac.Common.FixedArrays;
namespace LibHac.Bcat.Impl.Service.Core;
[StructLayout(LayoutKind.Explicit, Size = 0x80)]
internal struct DeliveryCacheFileMetaEntry
{
[FieldOffset(0x00)] public FileName Name;
[FieldOffset(0x20)] public long Id;
[FieldOffset(0x28)] public long Size;
[FieldOffset(0x30)] public Digest Digest;
public FileName Name;
public long Id;
public long Size;
public Digest Digest;
public Array64<byte> Reserved;
}

View File

@ -222,9 +222,9 @@ internal class DeliveryCacheStorageManager
AppendMountName(ref sb, applicationId);
sb.Append(DirectoriesPath)
.Append(DirectorySeparator).Append(directoryName.Bytes)
.Append(DirectorySeparator).Append(directoryName.Value)
.Append(DirectorySeparator).Append(FilesDirectoryName)
.Append(DirectorySeparator).Append(fileName.Bytes);
.Append(DirectorySeparator).Append(fileName.Value);
}
}
@ -237,7 +237,7 @@ internal class DeliveryCacheStorageManager
AppendMountName(ref sb, applicationId);
sb.Append(DirectoriesPath)
.Append(DirectorySeparator).Append(directoryName.Bytes)
.Append(DirectorySeparator).Append(directoryName.Value)
.Append(DirectorySeparator).Append(FilesMetaFileName);
}
}
@ -262,7 +262,7 @@ internal class DeliveryCacheStorageManager
AppendMountName(ref sb, applicationId);
sb.Append(DirectoriesPath)
.Append(DirectorySeparator).Append(directoryName.Bytes);
.Append(DirectorySeparator).Append(directoryName.Value);
}
}

View File

@ -75,7 +75,7 @@ internal class DeliveryCacheDirectoryService : IDeliveryCacheDirectoryService
break;
}
entryBuffer[i] = new DeliveryCacheDirectoryEntry(ref entry.Name, entry.Size, ref entry.Digest);
entryBuffer[i] = new DeliveryCacheDirectoryEntry(in entry.Name, entry.Size, in entry.Digest);
}
entriesRead = i;

View File

@ -76,7 +76,7 @@ internal class DeliveryCacheStorageService : IDeliveryCacheStorageService
break;
}
StringUtils.Copy(nameBuffer[i].Bytes, entry.Name.Bytes);
StringUtils.Copy(nameBuffer[i].Value.Items, entry.Name.Value);
}
namesRead = i;

View File

@ -0,0 +1,30 @@
#pragma warning disable CS0169, IDE0051 // Remove unused private members
using System;
using System.Runtime.CompilerServices;
namespace LibHac.Common.FixedArrays;
public struct Array11<T>
{
public const int Length = 11;
private T _1;
private T _2;
private T _3;
private T _4;
private T _5;
private T _6;
private T _7;
private T _8;
private T _9;
private T _10;
private T _11;
public ref T this[int i] => ref Items[i];
public Span<T> Items => SpanHelpers.CreateSpan(ref _1, Length);
public readonly ReadOnlySpan<T> ItemsRo => SpanHelpers.CreateReadOnlySpan(in _1, Length);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator ReadOnlySpan<T>(in Array11<T> value) => value.ItemsRo;
}

View 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 Array24<T>
{
public const int Length = 24;
private Array16<T> _0;
private Array8<T> _16;
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 Array24<T> value) => value.ItemsRo;
}

View 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 Array26<T>
{
public const int Length = 26;
private Array16<T> _0;
private Array8<T> _16;
private Array2<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 Array26<T> value) => value.ItemsRo;
}

View 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 Array36<T>
{
public const int Length = 36;
private Array32<T> _0;
private Array4<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 Array36<T> value) => value.ItemsRo;
}

View 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 Array400<T>
{
public const int Length = 400;
private Array256<T> _0;
private Array128<T> _256;
private Array16<T> _384;
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 Array400<T> value) => value.ItemsRo;
}

View File

@ -1,8 +1,7 @@
using System.Runtime.InteropServices;
using LibHac.Common.FixedArrays;
namespace LibHac.Fs;
[StructLayout(LayoutKind.Sequential, Size = 0x80)]
public struct MemoryReportInfo
{
public long PooledBufferFreeSizePeak;
@ -12,8 +11,10 @@ public struct MemoryReportInfo
public long BufferManagerRetriedCount;
public long ExpHeapFreeSizePeak;
public long BufferPoolFreeSizePeak;
public long PatrolAllocateSuccessCount;
public long PatrolAllocateFailureCount;
public long PatrolReadAllocateBufferSuccessCount;
public long PatrolReadAllocateBufferFailureCount;
public long BufferManagerTotalAllocatableSizePeak;
public long BufferPoolAllocateSizeMax;
public long PooledBufferFailedIdealAllocationCountOnAsyncAccess;
public Array32<byte> Reserved;
}

View File

@ -1,21 +1,21 @@
using System;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Common.FixedArrays;
using LibHac.FsSrv.Impl;
using LibHac.Ncm;
using LibHac.Util;
namespace LibHac.Fs;
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<SaveDataAttribute>
{
[FieldOffset(0x00)] public ProgramId ProgramId;
[FieldOffset(0x08)] public UserId UserId;
[FieldOffset(0x18)] public ulong StaticSaveDataId;
[FieldOffset(0x20)] public SaveDataType Type;
[FieldOffset(0x21)] public SaveDataRank Rank;
[FieldOffset(0x22)] public ushort Index;
public ProgramId ProgramId;
public UserId UserId;
public ulong StaticSaveDataId;
public SaveDataType Type;
public SaveDataRank Rank;
public ushort Index;
public Array24<byte> Reserved;
public SaveDataAttribute(ProgramId programId, SaveDataType type, UserId userId, ulong saveDataId) : this(
programId, type, userId, saveDataId, 0, SaveDataRank.Primary)
@ -34,6 +34,7 @@ public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<Sav
StaticSaveDataId = saveDataId;
Index = index;
Rank = rank;
Reserved = new Array24<byte>();
}
public static Result Make(out SaveDataAttribute attribute, ProgramId programId, SaveDataType type,
@ -109,16 +110,16 @@ public struct SaveDataAttribute : IEquatable<SaveDataAttribute>, IComparable<Sav
}
}
[StructLayout(LayoutKind.Explicit, Size = 0x40)]
public struct SaveDataCreationInfo
{
[FieldOffset(0x00)] public long Size;
[FieldOffset(0x08)] public long JournalSize;
[FieldOffset(0x10)] public long BlockSize;
[FieldOffset(0x18)] public ulong OwnerId;
[FieldOffset(0x20)] public SaveDataFlags Flags;
[FieldOffset(0x24)] public SaveDataSpaceId SpaceId;
[FieldOffset(0x25)] public bool IsPseudoSaveData;
public long Size;
public long JournalSize;
public long BlockSize;
public ulong OwnerId;
public SaveDataFlags Flags;
public SaveDataSpaceId SpaceId;
public bool IsPseudoSaveData;
public Array26<byte> Reserved;
public static Result Make(out SaveDataCreationInfo creationInfo, long size, long journalSize, ulong ownerId,
SaveDataFlags flags, SaveDataSpaceId spaceId)
@ -142,17 +143,16 @@ public struct SaveDataCreationInfo
}
}
[StructLayout(LayoutKind.Explicit, Size = 0x48)]
public struct SaveDataFilter
{
[FieldOffset(0x00)] public bool FilterByProgramId;
[FieldOffset(0x01)] public bool FilterBySaveDataType;
[FieldOffset(0x02)] public bool FilterByUserId;
[FieldOffset(0x03)] public bool FilterBySaveDataId;
[FieldOffset(0x04)] public bool FilterByIndex;
[FieldOffset(0x05)] public SaveDataRank Rank;
public bool FilterByProgramId;
public bool FilterBySaveDataType;
public bool FilterByUserId;
public bool FilterBySaveDataId;
public bool FilterByIndex;
public SaveDataRank Rank;
[FieldOffset(0x08)] public SaveDataAttribute Attribute;
public SaveDataAttribute Attribute;
public void SetProgramId(ProgramId value)
{
@ -245,49 +245,46 @@ public struct SaveDataFilter
}
}
[StructLayout(LayoutKind.Explicit, Size = HashLength)]
public struct HashSalt
{
private const int HashLength = 0x20;
private Array32<byte> _value;
[FieldOffset(0x00)] private byte _hashStart;
public Span<byte> Hash => SpanHelpers.CreateSpan(ref _hashStart, HashLength);
public ReadOnlySpan<byte> HashRo => SpanHelpers.CreateReadOnlySpan(in _hashStart, HashLength);
public Span<byte> Hash => _value.Items;
public readonly ReadOnlySpan<byte> HashRo => _value.ItemsRo;
}
[StructLayout(LayoutKind.Explicit, Size = 0x10)]
public struct SaveDataMetaInfo
{
[FieldOffset(0)] public int Size;
[FieldOffset(4)] public SaveDataMetaType Type;
public int Size;
public SaveDataMetaType Type;
public Array11<byte> Reserved;
}
[StructLayout(LayoutKind.Explicit, Size = 0x60)]
public struct SaveDataInfo
{
[FieldOffset(0x00)] public ulong SaveDataId;
[FieldOffset(0x08)] public SaveDataSpaceId SpaceId;
[FieldOffset(0x09)] public SaveDataType Type;
[FieldOffset(0x10)] public UserId UserId;
[FieldOffset(0x20)] public ulong StaticSaveDataId;
[FieldOffset(0x28)] public ProgramId ProgramId;
[FieldOffset(0x30)] public long Size;
[FieldOffset(0x38)] public ushort Index;
[FieldOffset(0x3A)] public SaveDataRank Rank;
[FieldOffset(0x3B)] public SaveDataState State;
public ulong SaveDataId;
public SaveDataSpaceId SpaceId;
public SaveDataType Type;
public UserId UserId;
public ulong StaticSaveDataId;
public ProgramId ProgramId;
public long Size;
public ushort Index;
public SaveDataRank Rank;
public SaveDataState State;
public Array36<byte> Reserved;
}
[StructLayout(LayoutKind.Explicit, Size = 0x200)]
public struct SaveDataExtraData
{
[FieldOffset(0x00)] public SaveDataAttribute Attribute;
[FieldOffset(0x40)] public ulong OwnerId;
[FieldOffset(0x48)] public long TimeStamp;
[FieldOffset(0x50)] public SaveDataFlags Flags;
[FieldOffset(0x58)] public long DataSize;
[FieldOffset(0x60)] public long JournalSize;
[FieldOffset(0x68)] public long CommitId;
public SaveDataAttribute Attribute;
public ulong OwnerId;
public long TimeStamp;
public SaveDataFlags Flags;
public long DataSize;
public long JournalSize;
public long CommitId;
public Array400<byte> Reserved;
}
public struct CommitOption

View File

@ -112,8 +112,8 @@ public class StatusReportServiceImpl
if (_config.GetPatrolAllocateCounts != null)
{
_config.GetPatrolAllocateCounts(out reportInfo.PatrolAllocateSuccessCount,
out reportInfo.PatrolAllocateFailureCount);
_config.GetPatrolAllocateCounts(out reportInfo.PatrolReadAllocateBufferSuccessCount,
out reportInfo.PatrolReadAllocateBufferFailureCount);
}
return Result.Success;

View File

@ -0,0 +1,23 @@
using System.Runtime.CompilerServices;
using LibHac.Arp;
using Xunit;
using static LibHac.Tests.Common.Layout;
namespace LibHac.Tests.Arp;
public class TypeLayoutTests
{
[Fact]
public static void ApplicationLaunchProperty_Layout()
{
var s = new ApplicationLaunchProperty();
Assert.Equal(0x10, Unsafe.SizeOf<ApplicationLaunchProperty>());
Assert.Equal(0x0, GetOffset(in s, in s.ApplicationId));
Assert.Equal(0x8, GetOffset(in s, in s.Version));
Assert.Equal(0xC, GetOffset(in s, in s.StorageId));
Assert.Equal(0xD, GetOffset(in s, in s.PatchStorageId));
Assert.Equal(0xE, GetOffset(in s, in s.ApplicationKind));
}
}

View File

@ -0,0 +1,78 @@
using System.Runtime.CompilerServices;
using LibHac.Bcat;
using LibHac.Bcat.Impl.Service.Core;
using Xunit;
using static LibHac.Tests.Common.Layout;
namespace LibHac.Tests.Bcat;
public class TypeLayoutTests
{
[Fact]
public static void Digest_Layout()
{
var s = new Digest();
Assert.Equal(0x10, Unsafe.SizeOf<Digest>());
Assert.Equal(0x0, GetOffset(in s, in s.Value));
}
[Fact]
public static void DirectoryName_Layout()
{
var s = new DirectoryName();
Assert.Equal(0x20, Unsafe.SizeOf<DirectoryName>());
Assert.Equal(0x0, GetOffset(in s, in s.Value));
}
[Fact]
public static void FileName_Layout()
{
var s = new FileName();
Assert.Equal(0x20, Unsafe.SizeOf<FileName>());
Assert.Equal(0x0, GetOffset(in s, in s.Value));
}
[Fact]
public static void DeliveryCacheDirectoryEntry_Layout()
{
var s = new DeliveryCacheDirectoryEntry();
Assert.Equal(0x38, Unsafe.SizeOf<DeliveryCacheDirectoryEntry>());
Assert.Equal(0x00, GetOffset(in s, in s.Name));
Assert.Equal(0x20, GetOffset(in s, in s.Size));
Assert.Equal(0x28, GetOffset(in s, in s.Digest));
}
[Fact]
public static void DeliveryCacheDirectoryMetaEntry_Layout()
{
var s = new DeliveryCacheDirectoryMetaEntry();
Assert.Equal(0x40, Unsafe.SizeOf<DeliveryCacheDirectoryMetaEntry>());
Assert.Equal(0x00, GetOffset(in s, in s.Name));
Assert.Equal(0x20, GetOffset(in s, in s.Digest));
Assert.Equal(0x30, GetOffset(in s, in s.Reserved));
}
[Fact]
public static void DeliveryCacheFileMetaEntry_Layout()
{
var s = new DeliveryCacheFileMetaEntry();
Assert.Equal(0x80, Unsafe.SizeOf<DeliveryCacheFileMetaEntry>());
Assert.Equal(0x00, GetOffset(in s, in s.Name));
Assert.Equal(0x20, GetOffset(in s, in s.Id));
Assert.Equal(0x28, GetOffset(in s, in s.Size));
Assert.Equal(0x30, GetOffset(in s, in s.Digest));
Assert.Equal(0x40, GetOffset(in s, in s.Reserved));
}
}

View File

@ -0,0 +1,149 @@
using System.Runtime.CompilerServices;
using LibHac.Fs;
using Xunit;
using static LibHac.Tests.Common.Layout;
namespace LibHac.Tests.Fs;
public class TypeLayoutTests
{
[Fact]
public static void SaveDataAttribute_Layout()
{
var s = new SaveDataAttribute();
Assert.Equal(0x40, Unsafe.SizeOf<SaveDataAttribute>());
Assert.Equal(0x00, GetOffset(in s, in s.ProgramId));
Assert.Equal(0x08, GetOffset(in s, in s.UserId));
Assert.Equal(0x18, GetOffset(in s, in s.StaticSaveDataId));
Assert.Equal(0x20, GetOffset(in s, in s.Type));
Assert.Equal(0x21, GetOffset(in s, in s.Rank));
Assert.Equal(0x22, GetOffset(in s, in s.Index));
Assert.Equal(0x24, GetOffset(in s, in s.Reserved));
}
[Fact]
public static void SaveDataCreationInfo_Layout()
{
var s = new SaveDataCreationInfo();
Assert.Equal(0x40, Unsafe.SizeOf<SaveDataCreationInfo>());
Assert.Equal(0x00, GetOffset(in s, in s.Size));
Assert.Equal(0x08, GetOffset(in s, in s.JournalSize));
Assert.Equal(0x10, GetOffset(in s, in s.BlockSize));
Assert.Equal(0x18, GetOffset(in s, in s.OwnerId));
Assert.Equal(0x20, GetOffset(in s, in s.Flags));
Assert.Equal(0x24, GetOffset(in s, in s.SpaceId));
Assert.Equal(0x25, GetOffset(in s, in s.IsPseudoSaveData));
Assert.Equal(0x26, GetOffset(in s, in s.Reserved));
}
[Fact]
public static void SaveDataFilter_Layout()
{
var s = new SaveDataFilter();
Assert.Equal(0x48, Unsafe.SizeOf<SaveDataFilter>());
Assert.Equal(0, GetOffset(in s, in s.FilterByProgramId));
Assert.Equal(1, GetOffset(in s, in s.FilterBySaveDataType));
Assert.Equal(2, GetOffset(in s, in s.FilterByUserId));
Assert.Equal(3, GetOffset(in s, in s.FilterBySaveDataId));
Assert.Equal(4, GetOffset(in s, in s.FilterByIndex));
Assert.Equal(5, GetOffset(in s, in s.Rank));
Assert.Equal(8, GetOffset(in s, in s.Attribute));
}
[Fact]
public static void SaveDataMetaInfo_Layout()
{
var s = new SaveDataMetaInfo();
Assert.Equal(0x10, Unsafe.SizeOf<SaveDataMetaInfo>());
Assert.Equal(0, GetOffset(in s, in s.Size));
Assert.Equal(4, GetOffset(in s, in s.Type));
Assert.Equal(5, GetOffset(in s, in s.Reserved));
}
[Fact]
public static void HashSalt_Layout()
{
var s = new HashSalt();
Assert.Equal(0x20, Unsafe.SizeOf<HashSalt>());
Assert.Equal(0, GetOffset(in s, in s.Hash[0]));
}
[Fact]
public static void SaveDataInfo_Layout()
{
var s = new SaveDataInfo();
Assert.Equal(0x60, Unsafe.SizeOf<SaveDataInfo>());
Assert.Equal(0x00, GetOffset(in s, in s.SaveDataId));
Assert.Equal(0x08, GetOffset(in s, in s.SpaceId));
Assert.Equal(0x09, GetOffset(in s, in s.Type));
Assert.Equal(0x10, GetOffset(in s, in s.UserId));
Assert.Equal(0x20, GetOffset(in s, in s.StaticSaveDataId));
Assert.Equal(0x28, GetOffset(in s, in s.ProgramId));
Assert.Equal(0x30, GetOffset(in s, in s.Size));
Assert.Equal(0x38, GetOffset(in s, in s.Index));
Assert.Equal(0x3A, GetOffset(in s, in s.Rank));
Assert.Equal(0x3B, GetOffset(in s, in s.State));
Assert.Equal(0x3C, GetOffset(in s, in s.Reserved));
}
[Fact]
public static void SaveDataExtraData_Layout()
{
var s = new SaveDataExtraData();
Assert.Equal(0x200, Unsafe.SizeOf<SaveDataExtraData>());
Assert.Equal(0x00, GetOffset(in s, in s.Attribute));
Assert.Equal(0x40, GetOffset(in s, in s.OwnerId));
Assert.Equal(0x48, GetOffset(in s, in s.TimeStamp));
Assert.Equal(0x50, GetOffset(in s, in s.Flags));
Assert.Equal(0x58, GetOffset(in s, in s.DataSize));
Assert.Equal(0x60, GetOffset(in s, in s.JournalSize));
Assert.Equal(0x68, GetOffset(in s, in s.CommitId));
Assert.Equal(0x70, GetOffset(in s, in s.Reserved));
}
[Fact]
public static void CommitOption_Layout()
{
var s = new CommitOption();
Assert.Equal(4, Unsafe.SizeOf<CommitOption>());
Assert.Equal(0, GetOffset(in s, in s.Flags));
}
[Fact]
public static void MemoryReportInfo_Layout()
{
var s = new MemoryReportInfo();
Assert.Equal(0x80, Unsafe.SizeOf<MemoryReportInfo>());
Assert.Equal(0x00, GetOffset(in s, in s.PooledBufferFreeSizePeak));
Assert.Equal(0x08, GetOffset(in s, in s.PooledBufferRetriedCount));
Assert.Equal(0x10, GetOffset(in s, in s.PooledBufferReduceAllocationCount));
Assert.Equal(0x18, GetOffset(in s, in s.BufferManagerFreeSizePeak));
Assert.Equal(0x20, GetOffset(in s, in s.BufferManagerRetriedCount));
Assert.Equal(0x28, GetOffset(in s, in s.ExpHeapFreeSizePeak));
Assert.Equal(0x30, GetOffset(in s, in s.BufferPoolFreeSizePeak));
Assert.Equal(0x38, GetOffset(in s, in s.PatrolReadAllocateBufferSuccessCount));
Assert.Equal(0x40, GetOffset(in s, in s.PatrolReadAllocateBufferFailureCount));
Assert.Equal(0x48, GetOffset(in s, in s.BufferManagerTotalAllocatableSizePeak));
Assert.Equal(0x50, GetOffset(in s, in s.BufferPoolAllocateSizeMax));
Assert.Equal(0x58, GetOffset(in s, in s.PooledBufferFailedIdealAllocationCountOnAsyncAccess));
Assert.Equal(0x60, GetOffset(in s, in s.Reserved));
}
}