From b0e679d00043d347b0f560c78b8de4210255691b Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 2 Jan 2022 16:52:57 -0700 Subject: [PATCH] Update struct layout of Ns structs --- src/LibHac/Common/FixedArrays/Array1024.cs | 31 ++ src/LibHac/Common/FixedArrays/Array2048.cs | 31 ++ src/LibHac/Common/FixedArrays/Array3000.cs | 34 ++ src/LibHac/Common/FixedArrays/Array37.cs | 31 ++ src/LibHac/Common/FixedArrays/Array65.cs | 31 ++ src/LibHac/Common/FixedArrays/Array768.cs | 31 ++ src/LibHac/Common/PaddingStructs.cs | 51 --- .../Fs/ApplicationSaveDataManagement.cs | 21 +- src/LibHac/Fs/Shim/Host.cs | 12 +- src/LibHac/FsSrv/Impl/LocationResolverSet.cs | 12 +- src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs | 2 +- src/LibHac/FsSystem/FsPath.cs | 42 -- src/LibHac/FsSystem/Hash.cs | 14 +- .../FsSystem/PartitionFileSystemCore.cs | 2 +- .../Kernel/InitialProcessBinaryReader.cs | 5 +- src/LibHac/Kernel/KipHeader.cs | 64 +-- src/LibHac/Lr/Path.cs | 19 +- src/LibHac/Ns/ApplicationControlProperty.cs | 428 +++++++++++------- src/LibHac/Tools/Fs/SwitchFs.cs | 2 +- .../LibHac.Tests/FsSystem/TypeLayoutTests.cs | 19 + tests/LibHac.Tests/Kernel/TypeLayoutTests.cs | 69 +++ tests/LibHac.Tests/Lr/TypeLayoutTests.cs | 19 + tests/LibHac.Tests/Ns/TypeLayoutTests.cs | 126 ++++++ 23 files changed, 759 insertions(+), 337 deletions(-) create mode 100644 src/LibHac/Common/FixedArrays/Array1024.cs create mode 100644 src/LibHac/Common/FixedArrays/Array2048.cs create mode 100644 src/LibHac/Common/FixedArrays/Array3000.cs create mode 100644 src/LibHac/Common/FixedArrays/Array37.cs create mode 100644 src/LibHac/Common/FixedArrays/Array65.cs create mode 100644 src/LibHac/Common/FixedArrays/Array768.cs delete mode 100644 src/LibHac/Common/PaddingStructs.cs delete mode 100644 src/LibHac/FsSystem/FsPath.cs create mode 100644 tests/LibHac.Tests/FsSystem/TypeLayoutTests.cs create mode 100644 tests/LibHac.Tests/Kernel/TypeLayoutTests.cs create mode 100644 tests/LibHac.Tests/Lr/TypeLayoutTests.cs create mode 100644 tests/LibHac.Tests/Ns/TypeLayoutTests.cs diff --git a/src/LibHac/Common/FixedArrays/Array1024.cs b/src/LibHac/Common/FixedArrays/Array1024.cs new file mode 100644 index 00000000..a1ef6dab --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array1024.cs @@ -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 Array1024 +{ + public const int Length = 1024; + + private Array512 _0; + private Array512 _512; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array1024 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/FixedArrays/Array2048.cs b/src/LibHac/Common/FixedArrays/Array2048.cs new file mode 100644 index 00000000..bfe46d18 --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array2048.cs @@ -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 Array2048 +{ + public const int Length = 2048; + + private Array1024 _0; + private Array1024 _1024; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array2048 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/FixedArrays/Array3000.cs b/src/LibHac/Common/FixedArrays/Array3000.cs new file mode 100644 index 00000000..bc1fd263 --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array3000.cs @@ -0,0 +1,34 @@ +#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 Array3000 +{ + public const int Length = 3000; + + private Array2048 _0; + private Array512 _2048; + private Array256 _2560; + private Array128 _2816; + private Array56 _2944; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array3000 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/FixedArrays/Array37.cs b/src/LibHac/Common/FixedArrays/Array37.cs new file mode 100644 index 00000000..4006cfb4 --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array37.cs @@ -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 Array37 +{ + public const int Length = 37; + + private Array32 _0; + private Array5 _32; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array37 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/FixedArrays/Array65.cs b/src/LibHac/Common/FixedArrays/Array65.cs new file mode 100644 index 00000000..08882816 --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array65.cs @@ -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 Array65 +{ + public const int Length = 65; + + private Array64 _0; + private T _64; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array65 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/FixedArrays/Array768.cs b/src/LibHac/Common/FixedArrays/Array768.cs new file mode 100644 index 00000000..1fb566c2 --- /dev/null +++ b/src/LibHac/Common/FixedArrays/Array768.cs @@ -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 Array768 +{ + public const int Length = 768; + + private Array512 _0; + private Array256 _512; + + public ref T this[int i] => ref Items[i]; + + public Span Items + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.Items), Length); + } + + public readonly ReadOnlySpan ItemsRo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => SpanHelpers.CreateSpan(ref MemoryMarshal.GetReference(_0.ItemsRo), Length); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(in Array768 value) => value.ItemsRo; +} \ No newline at end of file diff --git a/src/LibHac/Common/PaddingStructs.cs b/src/LibHac/Common/PaddingStructs.cs deleted file mode 100644 index d50c6435..00000000 --- a/src/LibHac/Common/PaddingStructs.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace LibHac.Common; - -// In order for the Visual Studio debugger to accurately display a struct, every offset -// in the struct that is used for the debugger display must be part of a field. -// These padding structs make it easier to accomplish that. -[StructLayout(LayoutKind.Sequential, Size = 0x10)] -internal struct Padding10 -{ - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding00; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding08; -} - -[StructLayout(LayoutKind.Sequential, Size = 0x20)] -internal struct Padding20 -{ - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding00; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding08; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding10; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong Padding18; -} - -[StructLayout(LayoutKind.Sequential, Size = 0x40)] -internal struct Padding40 -{ - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding20 Padding00; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding20 Padding20; -} - -[StructLayout(LayoutKind.Sequential, Size = 0x80)] -internal struct Padding80 -{ - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding40 Padding00; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding40 Padding40; -} - -[StructLayout(LayoutKind.Sequential, Size = 0x100)] -internal struct Padding100 -{ - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding80 Padding00; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding80 Padding80; -} - -[StructLayout(LayoutKind.Sequential, Size = 0x200)] -internal struct Padding200 -{ - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding000; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly Padding100 Padding100; -} diff --git a/src/LibHac/Fs/ApplicationSaveDataManagement.cs b/src/LibHac/Fs/ApplicationSaveDataManagement.cs index 84c67d03..2e13c0d0 100644 --- a/src/LibHac/Fs/ApplicationSaveDataManagement.cs +++ b/src/LibHac/Fs/ApplicationSaveDataManagement.cs @@ -3,7 +3,6 @@ using System.Diagnostics.CodeAnalysis; using LibHac.Account; using LibHac.Common; using LibHac.Fs.Shim; -using LibHac.Ncm; using LibHac.Ns; using LibHac.Util; @@ -18,7 +17,7 @@ public static class ApplicationSaveDataManagement long requiredSizeSum = 0; // Create local variable for use in closures - ProgramId saveDataOwnerId = nacp.SaveDataOwnerId; + ulong saveDataOwnerId = nacp.SaveDataOwnerId; // Ensure the user account save exists if (uid != Uid.Zero && nacp.UserAccountSaveDataSize > 0) @@ -31,7 +30,7 @@ public static class ApplicationSaveDataManagement Result CreateAccountSaveFunc() { UserId userId = ConvertAccountUidToFsUserId(uidLocal); - return fs.CreateSaveData(applicationId, userId, saveDataOwnerId.Value, accountSaveDataSize, + return fs.CreateSaveData(applicationId, userId, saveDataOwnerId, accountSaveDataSize, accountSaveJournalSize, SaveDataFlags.None); } @@ -53,8 +52,8 @@ public static class ApplicationSaveDataManagement long deviceSaveDataSize = nacp.DeviceSaveDataSize; long deviceSaveJournalSize = nacp.DeviceSaveDataJournalSize; - Result CreateDeviceSaveFunc() => fs.CreateDeviceSaveData(applicationId, saveDataOwnerId.Value, - deviceSaveDataSize, deviceSaveJournalSize, 0); + Result CreateDeviceSaveFunc() => fs.CreateDeviceSaveData(applicationId, saveDataOwnerId, deviceSaveDataSize, + deviceSaveJournalSize, 0); var filter = new SaveDataFilter(); filter.SetProgramId(applicationId); @@ -108,7 +107,7 @@ public static class ApplicationSaveDataManagement } else { - Result createRc = fs.CreateTemporaryStorage(applicationId, nacp.SaveDataOwnerId.Value, + Result createRc = fs.CreateTemporaryStorage(applicationId, nacp.SaveDataOwnerId, nacp.TemporaryStorageSize, 0); if (createRc.IsFailure()) @@ -311,7 +310,7 @@ public static class ApplicationSaveDataManagement public static Result EnsureApplicationCacheStorage(this FileSystemClient fs, out long requiredSize, Ncm.ApplicationId applicationId, ref ApplicationControlProperty nacp) { - return EnsureApplicationCacheStorageImpl(fs, out requiredSize, out _, applicationId, nacp.SaveDataOwnerId.Value, + return EnsureApplicationCacheStorageImpl(fs, out requiredSize, out _, applicationId, nacp.SaveDataOwnerId, 0, nacp.CacheStorageSize, nacp.CacheStorageJournalSize, true); } @@ -324,7 +323,7 @@ public static class ApplicationSaveDataManagement return Result.Success; return EnsureApplicationCacheStorageImpl(fs, out requiredSize, out target, applicationId, - nacp.SaveDataOwnerId.Value, 0, nacp.CacheStorageSize, nacp.CacheStorageJournalSize, true); + nacp.SaveDataOwnerId, 0, nacp.CacheStorageSize, nacp.CacheStorageJournalSize, true); } @@ -334,14 +333,14 @@ public static class ApplicationSaveDataManagement { UnsafeHelpers.SkipParamInit(out requiredSize, out target); - if (index > nacp.CacheStorageMaxIndex) + if (index > nacp.CacheStorageIndexMax) return ResultFs.CacheStorageIndexTooLarge.Log(); - if (dataSize + journalSize > nacp.CacheStorageMaxSizeAndMaxJournalSize) + if (dataSize + journalSize > nacp.CacheStorageDataAndJournalSizeMax) return ResultFs.CacheStorageSizeTooLarge.Log(); Result rc = fs.EnsureApplicationCacheStorage(out requiredSize, out target, applicationId, - nacp.SaveDataOwnerId.Value, index, dataSize, journalSize, false); + nacp.SaveDataOwnerId, index, dataSize, journalSize, false); fs.Impl.AbortIfNeeded(rc); return rc; diff --git a/src/LibHac/Fs/Shim/Host.cs b/src/LibHac/Fs/Shim/Host.cs index fabebedd..fe0d78b5 100644 --- a/src/LibHac/Fs/Shim/Host.cs +++ b/src/LibHac/Fs/Shim/Host.cs @@ -1,11 +1,11 @@ using System; using System.Runtime.CompilerServices; using LibHac.Common; +using LibHac.Common.FixedArrays; using LibHac.Diag; using LibHac.Fs.Fsa; using LibHac.Fs.Impl; using LibHac.FsSrv.Sf; -using LibHac.FsSystem; using LibHac.Os; using LibHac.Util; using static LibHac.Fs.StringTraits; @@ -65,11 +65,11 @@ public static class Host private class HostCommonMountNameGenerator : ICommonMountNameGenerator { - private FsPath _path; + private Array769 _path; public HostCommonMountNameGenerator(U8Span path) { - StringUtils.Strlcpy(_path.Str, path, FsPath.MaxLength + 1); + StringUtils.Strlcpy(_path.Items, path, PathTool.EntryNameLengthMax + 1); } public void Dispose() { } @@ -77,13 +77,13 @@ public static class Host public Result GenerateCommonMountName(Span nameBuffer) { int requiredNameBufferSize = - StringUtils.GetLength(_path.Str, FsPath.MaxLength + 1) + HostRootFileSystemPathLength; + StringUtils.GetLength(_path, PathTool.EntryNameLengthMax + 1) + HostRootFileSystemPathLength; if (nameBuffer.Length < requiredNameBufferSize) return ResultFs.TooLongPath.Log(); var sb = new U8StringBuilder(nameBuffer); - sb.Append(HostRootFileSystemPath).Append(_path.Str); + sb.Append(HostRootFileSystemPath).Append(_path); Assert.SdkEqual(sb.Length, requiredNameBufferSize - 1); @@ -533,4 +533,4 @@ public static class Host fs.Impl.LogResultErrorMessage(rc); Abort.DoAbortUnless(rc.IsSuccess()); } -} +} \ No newline at end of file diff --git a/src/LibHac/FsSrv/Impl/LocationResolverSet.cs b/src/LibHac/FsSrv/Impl/LocationResolverSet.cs index ca8b88f2..bf7ac043 100644 --- a/src/LibHac/FsSrv/Impl/LocationResolverSet.cs +++ b/src/LibHac/FsSrv/Impl/LocationResolverSet.cs @@ -79,10 +79,10 @@ internal class LocationResolverSet : IDisposable var pathFlags = new PathFlags(); pathFlags.AllowMountName(); - if (Utility.IsHostFsMountName(lrPath.Str)) + if (Utility.IsHostFsMountName(lrPath.Value)) pathFlags.AllowWindowsPath(); - Result rc = outPath.InitializeWithReplaceUnc(lrPath.Str); + Result rc = outPath.InitializeWithReplaceUnc(lrPath.Value); if (rc.IsFailure()) return rc; rc = outPath.Normalize(pathFlags); @@ -170,7 +170,7 @@ internal class LocationResolverSet : IDisposable rc = resolver.ResolveApplicationHtmlDocumentPath(out Lr.Path path, applicationId); if (rc.IsFailure()) return rc; - isDirectory = PathUtility.IsDirectoryPath(path.Str); + isDirectory = PathUtility.IsDirectoryPath(path.Value); return SetUpFsPath(ref outPath, in path); } @@ -185,7 +185,7 @@ internal class LocationResolverSet : IDisposable rc = resolver.ResolveProgramPath(out Lr.Path path, programId); if (rc.IsFailure()) return rc; - isDirectory = PathUtility.IsDirectoryPath(path.Str); + isDirectory = PathUtility.IsDirectoryPath(path.Value); return SetUpFsPath(ref outPath, in path); } @@ -200,7 +200,7 @@ internal class LocationResolverSet : IDisposable rc = resolver.ResolveProgramPathForDebug(out Lr.Path path, programId); if (rc.IsFailure()) return rc; - isDirectory = PathUtility.IsDirectoryPath(path.Str); + isDirectory = PathUtility.IsDirectoryPath(path.Value); return SetUpFsPath(ref outPath, in path); } @@ -291,4 +291,4 @@ internal class LocationResolverSet : IDisposable _ => -1 }; } -} +} \ No newline at end of file diff --git a/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs b/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs index 3a694bf7..85d4c7e8 100644 --- a/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs +++ b/src/LibHac/FsSrv/NcaFileSystemServiceImpl.cs @@ -474,7 +474,7 @@ public class NcaFileSystemServiceImpl return ResultFs.PathNotFound.Log(); } - if (StringUtils.GetLength(path, FsPath.MaxLength) == 0) + if (StringUtils.GetLength(path, PathTool.EntryNameLengthMax) == 0) { shouldContinue = false; } diff --git a/src/LibHac/FsSystem/FsPath.cs b/src/LibHac/FsSystem/FsPath.cs deleted file mode 100644 index 8bc24c03..00000000 --- a/src/LibHac/FsSystem/FsPath.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Util; - -namespace LibHac.FsSystem; - -[StructLayout(LayoutKind.Sequential, Size = MaxLength + 1)] -public struct FsPath -{ - 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 - - public Span Str => SpanHelpers.AsByteSpan(ref this); - - public static Result FromSpan(out FsPath fsPath, ReadOnlySpan path) - { - UnsafeHelpers.SkipParamInit(out fsPath); - - // Ensure null terminator even if the creation fails for safety - fsPath.Str[MaxLength] = 0; - - var sb = new U8StringBuilder(fsPath.Str); - bool overflowed = sb.Append(path).Overflowed; - - return overflowed ? ResultFs.TooLongPath.Log() : Result.Success; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator U8Span(in FsPath value) => new U8Span(SpanHelpers.AsReadOnlyByteSpan(in value)); - - public override string ToString() => StringUtils.Utf8ZToString(Str); -} \ No newline at end of file diff --git a/src/LibHac/FsSystem/Hash.cs b/src/LibHac/FsSystem/Hash.cs index 2cd0a907..3d9a2129 100644 --- a/src/LibHac/FsSystem/Hash.cs +++ b/src/LibHac/FsSystem/Hash.cs @@ -1,16 +1,8 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using LibHac.Common; +using LibHac.Common.FixedArrays; namespace LibHac.FsSystem; -[StructLayout(LayoutKind.Sequential, Size = 0x20)] public struct Hash { - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1; - - public readonly ReadOnlySpan Bytes => SpanHelpers.AsReadOnlyByteSpan(in this); - public Span BytesMutable => SpanHelpers.AsByteSpan(ref this); -} + public Array32 Value; +} \ No newline at end of file diff --git a/src/LibHac/FsSystem/PartitionFileSystemCore.cs b/src/LibHac/FsSystem/PartitionFileSystemCore.cs index 0ebac724..fe6aaa23 100644 --- a/src/LibHac/FsSystem/PartitionFileSystemCore.cs +++ b/src/LibHac/FsSystem/PartitionFileSystemCore.cs @@ -359,7 +359,7 @@ public class PartitionFileSystemCore : IFileSystem where T : unmanaged, IPart U8Span name = ParentFs._metaData.GetName(CurrentIndex); StringUtils.Copy(entryBuffer[i].Name.Items, name); - entryBuffer[i].Name[FsPath.MaxLength] = 0; + entryBuffer[i].Name[PathTool.EntryNameLengthMax] = 0; CurrentIndex++; } diff --git a/src/LibHac/Kernel/InitialProcessBinaryReader.cs b/src/LibHac/Kernel/InitialProcessBinaryReader.cs index c015c89b..f677d1b2 100644 --- a/src/LibHac/Kernel/InitialProcessBinaryReader.cs +++ b/src/LibHac/Kernel/InitialProcessBinaryReader.cs @@ -1,6 +1,5 @@ using System; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using LibHac.Common; using LibHac.Diag; using LibHac.Fs; @@ -96,8 +95,6 @@ public class InitialProcessBinaryReader : IDisposable return Result.Success; } - - [StructLayout(LayoutKind.Sequential, Size = 0x10)] public struct IniHeader { public uint Magic; @@ -105,4 +102,4 @@ public class InitialProcessBinaryReader : IDisposable public int ProcessCount; public uint Reserved; } -} +} \ No newline at end of file diff --git a/src/LibHac/Kernel/KipHeader.cs b/src/LibHac/Kernel/KipHeader.cs index 649e7cb3..a2a413b9 100644 --- a/src/LibHac/Kernel/KipHeader.cs +++ b/src/LibHac/Kernel/KipHeader.cs @@ -2,56 +2,57 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using LibHac.Common; +using LibHac.Common.FixedArrays; namespace LibHac.Kernel; -[StructLayout(LayoutKind.Explicit, Size = 0x100)] +[StructLayout(LayoutKind.Sequential)] public struct KipHeader { - public const uint Kip1Magic = 0x3150494B; // KIP1 - public const int NameSize = 12; - public const int SegmentCount = 6; + public static readonly uint Kip1Magic = 0x3150494B; // KIP1 + public static readonly int SegmentCount = 6; - [FieldOffset(0x00)] public uint Magic; + public uint Magic; - [FieldOffset(0x04)] private byte _name; + public Array12 Name; - [FieldOffset(0x10)] public ulong ProgramId; - [FieldOffset(0x18)] public int Version; + public ulong ProgramId; + public int Version; - [FieldOffset(0x1C)] public byte Priority; - [FieldOffset(0x1D)] public byte IdealCoreId; - [FieldOffset(0x1F)] public Flag Flags; + public byte Priority; + public byte IdealCoreId; + private byte _reserved1E; + public Flag Flags; - [FieldOffset(0x20)] public int TextMemoryOffset; - [FieldOffset(0x24)] public int TextSize; - [FieldOffset(0x28)] public int TextFileSize; + public int TextMemoryOffset; + public int TextSize; + public int TextFileSize; - [FieldOffset(0x2C)] public int AffinityMask; + public int AffinityMask; - [FieldOffset(0x30)] public int RoMemoryOffset; - [FieldOffset(0x34)] public int RoSize; - [FieldOffset(0x38)] public int RoFileSize; + public int RoMemoryOffset; + public int RoSize; + public int RoFileSize; - [FieldOffset(0x3C)] public int StackSize; + public int StackSize; - [FieldOffset(0x40)] public int DataMemoryOffset; - [FieldOffset(0x44)] public int DataSize; - [FieldOffset(0x48)] public int DataFileSize; + public int DataMemoryOffset; + public int DataSize; + public int DataFileSize; + private byte _reserved4C; - [FieldOffset(0x50)] public int BssMemoryOffset; - [FieldOffset(0x54)] public int BssSize; - [FieldOffset(0x58)] public int BssFileSize; + public int BssMemoryOffset; + public int BssSize; + public int BssFileSize; + private byte _reserved5C; - [FieldOffset(0x80)] private uint _capabilities; + private Array2 _unusedSegmentHeaders; - public Span Name => SpanHelpers.CreateSpan(ref _name, NameSize); + public Array32 Capabilities; public Span Segments => SpanHelpers.CreateSpan(ref Unsafe.As(ref TextMemoryOffset), SegmentCount); - public Span Capabilities => SpanHelpers.CreateSpan(ref _capabilities, 0x80 / sizeof(uint)); - public bool IsValid => Magic == Kip1Magic; [Flags] @@ -65,11 +66,12 @@ public struct KipHeader UseSecureMemory = 1 << 5 } - [StructLayout(LayoutKind.Sequential, Size = 0x10)] + [StructLayout(LayoutKind.Sequential)] public struct SegmentHeader { public int MemoryOffset; public int Size; public int FileSize; + private int _unused; } -} +} \ No newline at end of file diff --git a/src/LibHac/Lr/Path.cs b/src/LibHac/Lr/Path.cs index 444b6056..7b3ea32d 100644 --- a/src/LibHac/Lr/Path.cs +++ b/src/LibHac/Lr/Path.cs @@ -1,24 +1,13 @@ -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; using LibHac.Common; -using LibHac.Fs; +using LibHac.Common.FixedArrays; using LibHac.Util; namespace LibHac.Lr; -[StructLayout(LayoutKind.Sequential, Size = PathTool.EntryNameLengthMax)] public 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; -#endif - - public readonly ReadOnlySpan Str => SpanHelpers.AsReadOnlyByteSpan(in this); - public Span StrMutable => SpanHelpers.AsByteSpan(ref this); + public Array768 Value; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InitEmpty(out Path path) @@ -30,5 +19,5 @@ public struct Path [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator U8Span(in Path value) => new U8Span(SpanHelpers.AsReadOnlyByteSpan(in value)); - public readonly override string ToString() => StringUtils.Utf8ZToString(Str); + public readonly override string ToString() => StringUtils.Utf8ZToString(Value); } \ No newline at end of file diff --git a/src/LibHac/Ns/ApplicationControlProperty.cs b/src/LibHac/Ns/ApplicationControlProperty.cs index a0bc6eb7..4d856046 100644 --- a/src/LibHac/Ns/ApplicationControlProperty.cs +++ b/src/LibHac/Ns/ApplicationControlProperty.cs @@ -1,188 +1,302 @@ using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; using LibHac.Common; -using LibHac.Ncm; +using LibHac.Common.FixedArrays; namespace LibHac.Ns; -[StructLayout(LayoutKind.Explicit, Size = 0x4000)] public struct ApplicationControlProperty { - private const int TitleCount = 0x10; - private const int IsbnSize = 0x25; - private const int RatingAgeCount = 0x20; - private const int DisplayVersionSize = 0x10; - private const int ApplicationErrorCodeCategorySize = 8; - private const int LocalCommunicationIdCount = 8; - private const int Reserved30F3Size = 3; - private const int BcatPassphraseSize = 0x41; - private const int ReservedForUserAccountSaveDataOperationSize = 6; - private const int PlayLogQueryableApplicationIdCount = 0x10; - private const int ReceivableDataConfigurationCount = 0x10; + public Array16 Title; + public Array37 Isbn; + public StartupUserAccountValue StartupUserAccount; + public UserAccountSwitchLockValue UserAccountSwitchLock; + public AddOnContentRegistrationTypeValue AddOnContentRegistrationType; + public AttributeFlagValue AttributeFlag; + public uint SupportedLanguageFlag; + public ParentalControlFlagValue ParentalControlFlag; + public ScreenshotValue Screenshot; + public VideoCaptureValue VideoCapture; + public DataLossConfirmationValue DataLossConfirmation; + public PlayLogPolicyValue PlayLogPolicy; + public ulong PresenceGroupId; + public Array32 RatingAge; + public Array16 DisplayVersion; + public ulong AddOnContentBaseId; + public ulong SaveDataOwnerId; + public long UserAccountSaveDataSize; + public long UserAccountSaveDataJournalSize; + public long DeviceSaveDataSize; + public long DeviceSaveDataJournalSize; + public long BcatDeliveryCacheStorageSize; + public Array8 ApplicationErrorCodeCategory; + public Array8 LocalCommunicationId; + public LogoTypeValue LogoType; + public LogoHandlingValue LogoHandling; + public RuntimeAddOnContentInstallValue RuntimeAddOnContentInstall; + public RuntimeParameterDeliveryValue RuntimeParameterDelivery; + public Array2 Reserved30F4; + public CrashReportValue CrashReport; + public HdcpValue Hdcp; + public ulong SeedForPseudoDeviceId; + public Array65 BcatPassphrase; + public StartupUserAccountOptionFlagValue StartupUserAccountOption; + public Array6 ReservedForUserAccountSaveDataOperation; + public long UserAccountSaveDataSizeMax; + public long UserAccountSaveDataJournalSizeMax; + public long DeviceSaveDataSizeMax; + public long DeviceSaveDataJournalSizeMax; + public long TemporaryStorageSize; + public long CacheStorageSize; + public long CacheStorageJournalSize; + public long CacheStorageDataAndJournalSizeMax; + public ushort CacheStorageIndexMax; + public byte Reserved318A; + public byte RuntimeUpgrade; + public uint SupportingLimitedLicenses; + public Array16 PlayLogQueryableApplicationId; + public PlayLogQueryCapabilityValue PlayLogQueryCapability; + public RepairFlagValue RepairFlag; + public byte ProgramIndex; + public RequiredNetworkServiceLicenseOnLaunchValue RequiredNetworkServiceLicenseOnLaunchFlag; + public Array4 Reserved3214; + public ApplicationNeighborDetectionClientConfiguration NeighborDetectionClientConfiguration; + public ApplicationJitConfiguration JitConfiguration; + public RequiredAddOnContentsSetBinaryDescriptor RequiredAddOnContentsSetBinaryDescriptors; + public PlayReportPermissionValue PlayReportPermission; + public CrashScreenshotForProdValue CrashScreenshotForProd; + public CrashScreenshotForDevValue CrashScreenshotForDev; + public byte ContentsAvailabilityTransitionPolicy; + public Array4 Reserved3404; + public AccessibleLaunchRequiredVersionValue AccessibleLaunchRequiredVersion; + public Array3000 Reserved3448; - [FieldOffset(0x0000)] private byte _titles; - [FieldOffset(0x3000)] private byte _isbn; - [FieldOffset(0x3025)] public StartupUserAccount StartupUserAccount; - [FieldOffset(0x3026)] public byte UserAccountSwitchLock; - [FieldOffset(0x3027)] public byte AddOnContentRegistrationType; - [FieldOffset(0x3028)] public ApplicationAttribute ApplicationAttribute; - [FieldOffset(0x302C)] public uint SupportedLanguages; - [FieldOffset(0x3030)] public ParentalControlFlagValue ParentalControl; - [FieldOffset(0x3034)] public ScreenshotValue Screenshot; - [FieldOffset(0x3035)] public VideoCaptureValue VideoCaptureMode; - [FieldOffset(0x3036)] public byte DataLossConfirmation; - [FieldOffset(0x3037)] public byte PlayLogPolicy; - [FieldOffset(0x3038)] public ulong PresenceGroupId; - [FieldOffset(0x3040)] private sbyte _ratingAge; - [FieldOffset(0x3060)] private byte _displayVersion; - [FieldOffset(0x3070)] public ulong AddOnContentBaseId; - [FieldOffset(0x3078)] public ProgramId SaveDataOwnerId; - [FieldOffset(0x3080)] public long UserAccountSaveDataSize; - [FieldOffset(0x3088)] public long UserAccountSaveDataJournalSize; - [FieldOffset(0x3090)] public long DeviceSaveDataSize; - [FieldOffset(0x3098)] public long DeviceSaveDataJournalSize; - [FieldOffset(0x30A0)] public long BcatDeliveryCacheStorageSize; - [FieldOffset(0x30A8)] private byte _applicationErrorCodeCategory; - [FieldOffset(0x30B0)] private ulong _localCommunicationIds; - [FieldOffset(0x30F0)] public LogoType LogoType; - [FieldOffset(0x30F1)] public LogoHandling LogoHandling; - [FieldOffset(0x30F2)] public byte RuntimeAddOnContentInstall; - [FieldOffset(0x30F3)] public byte _reserved30F3; - [FieldOffset(0x30F6)] public byte CrashReport; - [FieldOffset(0x30F7)] public byte Hdcp; - [FieldOffset(0x30F8)] public ulong SeedForPseudoDeviceId; - [FieldOffset(0x3100)] private byte _bcatPassphrase; - [FieldOffset(0x3141)] public byte StartupUserAccountOption; - [FieldOffset(0x3142)] private byte _reservedForUserAccountSaveDataOperation; - [FieldOffset(0x3148)] public long UserAccountSaveDataMaxSize; - [FieldOffset(0x3150)] public long UserAccountSaveDataMaxJournalSize; - [FieldOffset(0x3158)] public long DeviceSaveDataMaxSize; - [FieldOffset(0x3160)] public long DeviceSaveDataMaxJournalSize; - [FieldOffset(0x3168)] public long TemporaryStorageSize; - [FieldOffset(0x3170)] public long CacheStorageSize; - [FieldOffset(0x3178)] public long CacheStorageJournalSize; - [FieldOffset(0x3180)] public long CacheStorageMaxSizeAndMaxJournalSize; - [FieldOffset(0x3188)] public long CacheStorageMaxIndex; - [FieldOffset(0x3190)] private ulong _playLogQueryableApplicationId; - [FieldOffset(0x3210)] public PlayLogQueryCapability PlayLogQueryCapability; - [FieldOffset(0x3211)] public byte RepairFlag; - [FieldOffset(0x3212)] public byte ProgramIndex; - [FieldOffset(0x3213)] public byte RequiredNetworkServiceLicenseOnLaunchFlag; - [FieldOffset(0x3214)] public uint Reserved3214; - [FieldOffset(0x3218)] public ApplicationControlDataConfiguration SendDataConfiguration; - [FieldOffset(0x3230)] private ApplicationControlDataConfiguration _receivableDataConfigurations; - [FieldOffset(0x32B0)] public ulong JitConfigurationFlag; - [FieldOffset(0x32B8)] public long MemorySize; + public struct ApplicationTitle + { + private Array512 _name; + private Array256 _publisher; - [FieldOffset(0x3000), DebuggerBrowsable(DebuggerBrowsableState.Never)] private Padding200 _padding1; - [FieldOffset(0x3200), DebuggerBrowsable(DebuggerBrowsableState.Never)] private Padding100 _padding2; + public U8SpanMutable Name => new U8SpanMutable(_name.Items); + public U8SpanMutable Publisher => new U8SpanMutable(_publisher.Items); + } - public Span Titles => SpanHelpers.CreateSpan(ref Unsafe.As(ref _titles), TitleCount); - public U8SpanMutable Isbn => new U8SpanMutable(SpanHelpers.CreateSpan(ref _isbn, IsbnSize)); - public Span RatingAge => SpanHelpers.CreateSpan(ref _ratingAge, RatingAgeCount); - public U8SpanMutable DisplayVersion => new U8SpanMutable(SpanHelpers.CreateSpan(ref _displayVersion, DisplayVersionSize)); + public struct ApplicationNeighborDetectionClientConfiguration + { + public ApplicationNeighborDetectionGroupConfiguration SendGroupConfiguration; + public Array16 ReceivableGroupConfigurations; + } - public U8SpanMutable ApplicationErrorCodeCategory => - new U8SpanMutable(SpanHelpers.CreateSpan(ref _applicationErrorCodeCategory, - ApplicationErrorCodeCategorySize)); + public struct ApplicationNeighborDetectionGroupConfiguration + { + public ulong GroupId; + public Array16 Key; + } - public Span LocalCommunicationIds => SpanHelpers.CreateSpan(ref _localCommunicationIds, LocalCommunicationIdCount); - public Span Reserved30F3 => SpanHelpers.CreateSpan(ref _reserved30F3, Reserved30F3Size); - public U8SpanMutable BcatPassphrase => new U8SpanMutable(SpanHelpers.CreateSpan(ref _bcatPassphrase, BcatPassphraseSize)); + public struct ApplicationJitConfiguration + { + public JitConfigurationFlag Flags; + public long MemorySize; + } - public Span ReservedForUserAccountSaveDataOperation => - SpanHelpers.CreateSpan(ref _reservedForUserAccountSaveDataOperation, - ReservedForUserAccountSaveDataOperationSize); + public struct RequiredAddOnContentsSetBinaryDescriptor + { + public Array32 Descriptors; + } - public Span PlayLogQueryableApplicationId => - SpanHelpers.CreateSpan(ref _playLogQueryableApplicationId, PlayLogQueryableApplicationIdCount); + public struct AccessibleLaunchRequiredVersionValue + { + public Array8 ApplicationId; + } - public Span ReceivableDataConfigurations => - SpanHelpers.CreateSpan(ref _receivableDataConfigurations, ReceivableDataConfigurationCount); -} + public enum Language + { + AmericanEnglish = 0, + BritishEnglish = 1, + Japanese = 2, + French = 3, + German = 4, + LatinAmericanSpanish = 5, + Spanish = 6, + Italian = 7, + Dutch = 8, + CanadianFrench = 9, + Portuguese = 10, + Russian = 11, + Korean = 12, + TraditionalChinese = 13, + SimplifiedChinese = 14, + BrazilianPortuguese = 15 + } -[StructLayout(LayoutKind.Explicit, Size = 0x300)] -public struct ApplicationControlTitle -{ - private const int NameLength = 0x200; - private const int PublisherLength = 0x100; + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum Organization + { + CERO = 0, + GRACGCRB = 1, + GSRMR = 2, + ESRB = 3, + ClassInd = 4, + USK = 5, + PEGI = 6, + PEGIPortugal = 7, + PEGIBBFC = 8, + Russian = 9, + ACB = 10, + OFLC = 11, + IARCGeneric = 12 + } - [FieldOffset(0x000)] private byte _name; - [FieldOffset(0x200)] private byte _publisher; + public enum StartupUserAccountValue : byte + { + None = 0, + Required = 1, + RequiredWithNetworkServiceAccountAvailable = 2 + } - [FieldOffset(0x000), DebuggerBrowsable(DebuggerBrowsableState.Never)] - private Padding200 _padding0; + public enum UserAccountSwitchLockValue : byte + { + Disable = 0, + Enable = 1 + } - [FieldOffset(0x200), DebuggerBrowsable(DebuggerBrowsableState.Never)] - private Padding100 _padding200; + public enum AddOnContentRegistrationTypeValue : byte + { + AllOnLaunch = 0, + OnDemand = 1 + } - public U8SpanMutable Name => new U8SpanMutable(SpanHelpers.CreateSpan(ref _name, NameLength)); - public U8SpanMutable Publisher => new U8SpanMutable(SpanHelpers.CreateSpan(ref _publisher, PublisherLength)); -} + [Flags] + public enum AttributeFlagValue + { + None = 0, + Demo = 1 << 0, + RetailInteractiveDisplay = 1 << 1, + } -[StructLayout(LayoutKind.Explicit, Size = 0x18)] -public struct ApplicationControlDataConfiguration -{ - [FieldOffset(0)] public ulong Id; - [FieldOffset(8)] private byte _key; + public enum ParentalControlFlagValue + { + None = 0, + FreeCommunication = 1 + } - [FieldOffset(8), DebuggerBrowsable(DebuggerBrowsableState.Never)] - private Padding10 _keyPadding; + public enum ScreenshotValue : byte + { + Allow = 0, + Deny = 1 + } - public Span Key => SpanHelpers.CreateSpan(ref _key, 0x10); -} + public enum VideoCaptureValue : byte + { + Disable = 0, + Manual = 1, + Enable = 2 + } -public enum StartupUserAccount : byte -{ - None = 0, - Required = 1, - RequiredWithNetworkServiceAccountAvailable = 2 -} + public enum DataLossConfirmationValue : byte + { + None = 0, + Required = 1 + } -public enum LogoHandling : byte -{ - Auto = 0, - Manual = 1 -} + public enum PlayLogPolicyValue : byte + { + Open = 0, + LogOnly = 1, + None = 2, + Closed = 3, + All = 0 + } -public enum LogoType : byte -{ - LicensedByNintendo = 0, - DistributedByNintendo = 1, - Nintendo = 2 -} + public enum LogoTypeValue : byte + { + LicensedByNintendo = 0, + DistributedByNintendo = 1, + Nintendo = 2 + } -[Flags] -public enum ApplicationAttribute -{ - None = 0, - Demo = 1 -} + public enum LogoHandlingValue : byte + { + Auto = 0, + Manual = 1 + } -public enum PlayLogQueryCapability : byte -{ - None = 0, - WhiteList = 1, - All = 2 -} + public enum RuntimeAddOnContentInstallValue : byte + { + Deny = 0, + AllowAppend = 1, + AllowAppendButDontDownloadWhenUsingNetwork = 2 + } -public enum ParentalControlFlagValue -{ - None = 0, - FreeCommunication = 1 -} + public enum RuntimeParameterDeliveryValue : byte + { + Always = 0, + AlwaysIfUserStateMatched = 1, + OnRestart = 2 + } -public enum ScreenshotValue : byte -{ - Allow = 0, - Deny = 1 -} + public enum CrashReportValue : byte + { + Deny = 0, + Allow = 1 + } -public enum VideoCaptureValue : byte -{ - Deny = 0, - Allow = 1, - Automatic = 2 -} + public enum HdcpValue : byte + { + None = 0, + Required = 1 + } + + [Flags] + public enum StartupUserAccountOptionFlagValue : byte + { + None = 0, + IsOptional = 1 << 0 + } + + public enum PlayLogQueryCapabilityValue : byte + { + None = 0, + WhiteList = 1, + All = 2 + } + + [Flags] + public enum RepairFlagValue : byte + { + None = 0, + SuppressGameCardAccess = 1 << 0 + } + + [Flags] + public enum RequiredNetworkServiceLicenseOnLaunchValue : byte + { + None = 0, + Common = 1 << 0 + } + + [Flags] + public enum JitConfigurationFlag : ulong + { + None = 0, + Enabled = 1 << 0 + } + + [Flags] + public enum PlayReportPermissionValue : byte + { + None = 0, + TargetMarketing = 1 << 0 + } + + public enum CrashScreenshotForProdValue : byte + { + Deny = 0, + Allow = 1 + } + + public enum CrashScreenshotForDevValue : byte + { + Deny = 0, + Allow = 1 + } +} \ No newline at end of file diff --git a/src/LibHac/Tools/Fs/SwitchFs.cs b/src/LibHac/Tools/Fs/SwitchFs.cs index 0eaf2d74..5f109d6a 100644 --- a/src/LibHac/Tools/Fs/SwitchFs.cs +++ b/src/LibHac/Tools/Fs/SwitchFs.cs @@ -229,7 +229,7 @@ public class SwitchFs : IDisposable control.Get.Read(out _, 0, title.Control.ByteSpan).ThrowIfFailure(); } - foreach (ref ApplicationControlTitle desc in title.Control.Value.Titles) + foreach (ref readonly ApplicationControlProperty.ApplicationTitle desc in title.Control.Value.Title.ItemsRo) { if (!desc.Name.IsEmpty()) { diff --git a/tests/LibHac.Tests/FsSystem/TypeLayoutTests.cs b/tests/LibHac.Tests/FsSystem/TypeLayoutTests.cs new file mode 100644 index 00000000..2a31de87 --- /dev/null +++ b/tests/LibHac.Tests/FsSystem/TypeLayoutTests.cs @@ -0,0 +1,19 @@ +using System.Runtime.CompilerServices; +using LibHac.FsSystem; +using Xunit; +using static LibHac.Tests.Common.Layout; + +namespace LibHac.Tests.FsSystem; + +public class TypeLayoutTests +{ + [Fact] + public static void Hash_Layout() + { + var s = new Hash(); + + Assert.Equal(0x20, Unsafe.SizeOf()); + + Assert.Equal(0x0, GetOffset(in s, in s.Value)); + } +} \ No newline at end of file diff --git a/tests/LibHac.Tests/Kernel/TypeLayoutTests.cs b/tests/LibHac.Tests/Kernel/TypeLayoutTests.cs new file mode 100644 index 00000000..4341fd75 --- /dev/null +++ b/tests/LibHac.Tests/Kernel/TypeLayoutTests.cs @@ -0,0 +1,69 @@ +using System.Runtime.CompilerServices; +using LibHac.Kernel; +using Xunit; +using static LibHac.Kernel.InitialProcessBinaryReader; +using static LibHac.Kernel.KipHeader; +using static LibHac.Tests.Common.Layout; + +namespace LibHac.Tests.Kernel; + +public class TypeLayoutTests +{ + [Fact] + public static void IniHeader_Layout() + { + var s = new IniHeader(); + + Assert.Equal(0x10, Unsafe.SizeOf()); + + Assert.Equal(0x0, GetOffset(in s, in s.Magic)); + Assert.Equal(0x4, GetOffset(in s, in s.Size)); + Assert.Equal(0x8, GetOffset(in s, in s.ProcessCount)); + Assert.Equal(0xC, GetOffset(in s, in s.Reserved)); + } + + [Fact] + public static void KipHeader_Layout() + { + var s = new KipHeader(); + + Assert.Equal(0x100, Unsafe.SizeOf()); + + Assert.Equal(0x00, GetOffset(in s, in s.Magic)); + Assert.Equal(0x04, GetOffset(in s, in s.Name)); + Assert.Equal(0x10, GetOffset(in s, in s.ProgramId)); + Assert.Equal(0x18, GetOffset(in s, in s.Version)); + Assert.Equal(0x1C, GetOffset(in s, in s.Priority)); + Assert.Equal(0x1D, GetOffset(in s, in s.IdealCoreId)); + Assert.Equal(0x1F, GetOffset(in s, in s.Flags)); + Assert.Equal(0x20, GetOffset(in s, in s.TextMemoryOffset)); + Assert.Equal(0x24, GetOffset(in s, in s.TextSize)); + Assert.Equal(0x28, GetOffset(in s, in s.TextFileSize)); + Assert.Equal(0x2C, GetOffset(in s, in s.AffinityMask)); + Assert.Equal(0x30, GetOffset(in s, in s.RoMemoryOffset)); + Assert.Equal(0x34, GetOffset(in s, in s.RoSize)); + Assert.Equal(0x38, GetOffset(in s, in s.RoFileSize)); + Assert.Equal(0x3C, GetOffset(in s, in s.StackSize)); + Assert.Equal(0x40, GetOffset(in s, in s.DataMemoryOffset)); + Assert.Equal(0x44, GetOffset(in s, in s.DataSize)); + Assert.Equal(0x48, GetOffset(in s, in s.DataFileSize)); + Assert.Equal(0x50, GetOffset(in s, in s.BssMemoryOffset)); + Assert.Equal(0x54, GetOffset(in s, in s.BssSize)); + Assert.Equal(0x58, GetOffset(in s, in s.BssFileSize)); + Assert.Equal(0x80, GetOffset(in s, in s.Capabilities)); + + Assert.Equal(0x20, GetOffset(in s, in s.Segments[0])); + } + + [Fact] + public static void KipSegmentHeader_Layout() + { + var s = new SegmentHeader(); + + Assert.Equal(0x10, Unsafe.SizeOf()); + + Assert.Equal(0x0, GetOffset(in s, in s.MemoryOffset)); + Assert.Equal(0x4, GetOffset(in s, in s.Size)); + Assert.Equal(0x8, GetOffset(in s, in s.FileSize)); + } +} \ No newline at end of file diff --git a/tests/LibHac.Tests/Lr/TypeLayoutTests.cs b/tests/LibHac.Tests/Lr/TypeLayoutTests.cs new file mode 100644 index 00000000..6b8da1b0 --- /dev/null +++ b/tests/LibHac.Tests/Lr/TypeLayoutTests.cs @@ -0,0 +1,19 @@ +using System.Runtime.CompilerServices; +using LibHac.Lr; +using Xunit; +using static LibHac.Tests.Common.Layout; + +namespace LibHac.Tests.Lr; + +public class TypeLayoutTests +{ + [Fact] + public static void IniHeader_Layout() + { + var s = new Path(); + + Assert.Equal(0x300, Unsafe.SizeOf()); + + Assert.Equal(0x0, GetOffset(in s, in s.Value)); + } +} \ No newline at end of file diff --git a/tests/LibHac.Tests/Ns/TypeLayoutTests.cs b/tests/LibHac.Tests/Ns/TypeLayoutTests.cs new file mode 100644 index 00000000..88fc2df1 --- /dev/null +++ b/tests/LibHac.Tests/Ns/TypeLayoutTests.cs @@ -0,0 +1,126 @@ +using System.Runtime.CompilerServices; +using LibHac.Ns; +using Xunit; +using static LibHac.Ns.ApplicationControlProperty; +using static LibHac.Tests.Common.Layout; + +namespace LibHac.Tests.Ns; + +public class TypeLayoutTests +{ + [Fact] + public static void ApplicationTitle_Layout() + { + var s = new ApplicationTitle(); + + Assert.Equal(0x300, Unsafe.SizeOf()); + + Assert.Equal(0x000, GetOffset(in s, in s.Name.Value[0])); + Assert.Equal(0x200, GetOffset(in s, in s.Publisher.Value[0])); + } + + [Fact] + public static void ApplicationNeighborDetectionGroupConfiguration_Layout() + { + var s = new ApplicationNeighborDetectionGroupConfiguration(); + + Assert.Equal(0x18, Unsafe.SizeOf()); + + Assert.Equal(0x0, GetOffset(in s, in s.GroupId)); + Assert.Equal(0x8, GetOffset(in s, in s.Key)); + } + + [Fact] + public static void ApplicationNeighborDetectionClientConfiguration_Layout() + { + var s = new ApplicationNeighborDetectionClientConfiguration(); + + Assert.Equal(0x198, Unsafe.SizeOf()); + + Assert.Equal(0x00, GetOffset(in s, in s.SendGroupConfiguration)); + Assert.Equal(0x18, GetOffset(in s, in s.ReceivableGroupConfigurations)); + } + + [Fact] + public static void ApplicationJitConfiguration_Layout() + { + var s = new ApplicationJitConfiguration(); + + Assert.Equal(0x10, Unsafe.SizeOf()); + + Assert.Equal(0x0, GetOffset(in s, in s.Flags)); + Assert.Equal(0x8, GetOffset(in s, in s.MemorySize)); + } + + [Fact] + public static void ApplicationControlProperty_Layout() + { + var s = new ApplicationControlProperty(); + + Assert.Equal(0x4000, Unsafe.SizeOf()); + + Assert.Equal(0x0000, GetOffset(in s, in s.Title)); + Assert.Equal(0x3000, GetOffset(in s, in s.Isbn)); + Assert.Equal(0x3025, GetOffset(in s, in s.StartupUserAccount)); + Assert.Equal(0x3026, GetOffset(in s, in s.UserAccountSwitchLock)); + Assert.Equal(0x3027, GetOffset(in s, in s.AddOnContentRegistrationType)); + Assert.Equal(0x3028, GetOffset(in s, in s.AttributeFlag)); + Assert.Equal(0x302C, GetOffset(in s, in s.SupportedLanguageFlag)); + Assert.Equal(0x3030, GetOffset(in s, in s.ParentalControlFlag)); + Assert.Equal(0x3034, GetOffset(in s, in s.Screenshot)); + Assert.Equal(0x3035, GetOffset(in s, in s.VideoCapture)); + Assert.Equal(0x3036, GetOffset(in s, in s.DataLossConfirmation)); + Assert.Equal(0x3037, GetOffset(in s, in s.PlayLogPolicy)); + Assert.Equal(0x3038, GetOffset(in s, in s.PresenceGroupId)); + Assert.Equal(0x3040, GetOffset(in s, in s.RatingAge)); + Assert.Equal(0x3060, GetOffset(in s, in s.DisplayVersion)); + Assert.Equal(0x3070, GetOffset(in s, in s.AddOnContentBaseId)); + Assert.Equal(0x3078, GetOffset(in s, in s.SaveDataOwnerId)); + Assert.Equal(0x3080, GetOffset(in s, in s.UserAccountSaveDataSize)); + Assert.Equal(0x3088, GetOffset(in s, in s.UserAccountSaveDataJournalSize)); + Assert.Equal(0x3090, GetOffset(in s, in s.DeviceSaveDataSize)); + Assert.Equal(0x3098, GetOffset(in s, in s.DeviceSaveDataJournalSize)); + Assert.Equal(0x30A0, GetOffset(in s, in s.BcatDeliveryCacheStorageSize)); + Assert.Equal(0x30A8, GetOffset(in s, in s.ApplicationErrorCodeCategory)); + Assert.Equal(0x30B0, GetOffset(in s, in s.LocalCommunicationId)); + Assert.Equal(0x30F0, GetOffset(in s, in s.LogoType)); + Assert.Equal(0x30F1, GetOffset(in s, in s.LogoHandling)); + Assert.Equal(0x30F2, GetOffset(in s, in s.RuntimeAddOnContentInstall)); + Assert.Equal(0x30F3, GetOffset(in s, in s.RuntimeParameterDelivery)); + Assert.Equal(0x30F4, GetOffset(in s, in s.Reserved30F4)); + Assert.Equal(0x30F6, GetOffset(in s, in s.CrashReport)); + Assert.Equal(0x30F7, GetOffset(in s, in s.Hdcp)); + Assert.Equal(0x30F8, GetOffset(in s, in s.SeedForPseudoDeviceId)); + Assert.Equal(0x3100, GetOffset(in s, in s.BcatPassphrase)); + Assert.Equal(0x3141, GetOffset(in s, in s.StartupUserAccountOption)); + Assert.Equal(0x3142, GetOffset(in s, in s.ReservedForUserAccountSaveDataOperation)); + Assert.Equal(0x3148, GetOffset(in s, in s.UserAccountSaveDataSizeMax)); + Assert.Equal(0x3150, GetOffset(in s, in s.UserAccountSaveDataJournalSizeMax)); + Assert.Equal(0x3158, GetOffset(in s, in s.DeviceSaveDataSizeMax)); + Assert.Equal(0x3160, GetOffset(in s, in s.DeviceSaveDataJournalSizeMax)); + Assert.Equal(0x3168, GetOffset(in s, in s.TemporaryStorageSize)); + Assert.Equal(0x3170, GetOffset(in s, in s.CacheStorageSize)); + Assert.Equal(0x3178, GetOffset(in s, in s.CacheStorageJournalSize)); + Assert.Equal(0x3180, GetOffset(in s, in s.CacheStorageDataAndJournalSizeMax)); + Assert.Equal(0x3188, GetOffset(in s, in s.CacheStorageIndexMax)); + Assert.Equal(0x318A, GetOffset(in s, in s.Reserved318A)); + Assert.Equal(0x318B, GetOffset(in s, in s.RuntimeUpgrade)); + Assert.Equal(0x318C, GetOffset(in s, in s.SupportingLimitedLicenses)); + Assert.Equal(0x3190, GetOffset(in s, in s.PlayLogQueryableApplicationId)); + Assert.Equal(0x3210, GetOffset(in s, in s.PlayLogQueryCapability)); + Assert.Equal(0x3211, GetOffset(in s, in s.RepairFlag)); + Assert.Equal(0x3212, GetOffset(in s, in s.ProgramIndex)); + Assert.Equal(0x3213, GetOffset(in s, in s.RequiredNetworkServiceLicenseOnLaunchFlag)); + Assert.Equal(0x3214, GetOffset(in s, in s.Reserved3214)); + Assert.Equal(0x3218, GetOffset(in s, in s.NeighborDetectionClientConfiguration)); + Assert.Equal(0x33B0, GetOffset(in s, in s.JitConfiguration)); + Assert.Equal(0x33C0, GetOffset(in s, in s.RequiredAddOnContentsSetBinaryDescriptors)); + Assert.Equal(0x3400, GetOffset(in s, in s.PlayReportPermission)); + Assert.Equal(0x3401, GetOffset(in s, in s.CrashScreenshotForProd)); + Assert.Equal(0x3402, GetOffset(in s, in s.CrashScreenshotForDev)); + Assert.Equal(0x3403, GetOffset(in s, in s.ContentsAvailabilityTransitionPolicy)); + Assert.Equal(0x3404, GetOffset(in s, in s.Reserved3404)); + Assert.Equal(0x3408, GetOffset(in s, in s.AccessibleLaunchRequiredVersion)); + Assert.Equal(0x3448, GetOffset(in s, in s.Reserved3448)); + } +} \ No newline at end of file