diff --git a/src/LibHac/Fs/RomFs/HierarchicalRomFileTable.cs b/src/LibHac/Fs/RomFs/HierarchicalRomFileTable.cs index a9b7f033..b73b2efd 100644 --- a/src/LibHac/Fs/RomFs/HierarchicalRomFileTable.cs +++ b/src/LibHac/Fs/RomFs/HierarchicalRomFileTable.cs @@ -6,11 +6,13 @@ namespace LibHac.Fs.RomFs /// /// Represents the file table used by the RomFS format. /// + /// The type of the value to be stored for each file entry. /// /// This file table stores the structure of the file tree in a RomFS. /// Each file or directory entry is stored in the table using its full path as a key. /// Once added, a file or directory is assigned an ID that can also be used to retrieve it. - /// Each file entry contains the size of the file and its offset in the RomFS. + /// Each file entry contains a structure of type . + /// In a standard RomFS, this includes the size of the file and its offset in the RomFS. /// Each directory entry contains the IDs for its first child file and first child directory. /// /// The table is represented by four byte arrays. Two of the arrays contain the hash buckets and @@ -19,13 +21,13 @@ namespace LibHac.Fs.RomFs /// Once all files have been added to the table, should be called /// to optimize the size of the table. /// - public class HierarchicalRomFileTable + public class HierarchicalRomFileTable where T : unmanaged { private RomFsDictionary FileTable { get; } private RomFsDictionary DirectoryTable { get; } /// - /// Initializes a from an existing table. + /// Initializes a from an existing table. /// /// /// @@ -39,17 +41,17 @@ namespace LibHac.Fs.RomFs } /// - /// Initializes a new that has the default initial capacity. + /// Initializes a new that has the default initial capacity. /// public HierarchicalRomFileTable() : this(0, 0) { } /// - /// Initializes a new that has the specified initial capacity. + /// Initializes a new that has the specified initial capacity. /// /// The initial number of directories that the - /// can contain. + /// can contain. /// The initial number of files that the - /// can contain. + /// can contain. public HierarchicalRomFileTable(int directoryCapacity, int fileCapacity) { FileTable = new RomFsDictionary(fileCapacity); @@ -78,7 +80,7 @@ namespace LibHac.Fs.RomFs return FileTable.GetEntryData().ToArray(); } - public bool TryOpenFile(string path, out RomFileInfo fileInfo) + public bool TryOpenFile(string path, out T fileInfo) { FindPathRecursive(Util.GetUtf8Bytes(path), out RomEntryKey key); @@ -92,7 +94,7 @@ namespace LibHac.Fs.RomFs return false; } - public bool TryOpenFile(int fileId, out RomFileInfo fileInfo) + public bool TryOpenFile(int fileId, out T fileInfo) { if (FileTable.TryGetValue(fileId, out RomKeyValuePair keyValuePair)) { @@ -153,7 +155,7 @@ namespace LibHac.Fs.RomFs /// When this method returns, contains the file's name (Not the full path). /// if the next file was successfully returned. /// if there are no more files to enumerate. - public bool FindNextFile(ref FindPosition position, out RomFileInfo info, out string name) + public bool FindNextFile(ref FindPosition position, out T info, out string name) { if (position.NextFile == -1) { @@ -201,7 +203,7 @@ namespace LibHac.Fs.RomFs /// /// The full path of the file to be added. /// The file information to be stored. - public void AddFile(string path, ref RomFileInfo fileInfo) + public void AddFile(string path, ref T fileInfo) { path = PathTools.Normalize(path); ReadOnlySpan pathBytes = Util.GetUtf8Bytes(path); @@ -288,7 +290,7 @@ namespace LibHac.Fs.RomFs } } - private void CreateFileRecursiveInternal(ReadOnlySpan path, ref RomFileInfo fileInfo) + private void CreateFileRecursiveInternal(ReadOnlySpan path, ref T fileInfo) { var parser = new PathParser(path); var key = new RomEntryKey(); @@ -367,18 +369,18 @@ namespace LibHac.Fs.RomFs } } - [StructLayout(LayoutKind.Sequential, Pack = 4)] + [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct DirectoryRomEntry { public int NextSibling; public FindPosition Pos; } - [StructLayout(LayoutKind.Sequential, Pack = 4)] + [StructLayout(LayoutKind.Sequential, Pack = 1)] private struct FileRomEntry { public int NextSibling; - public RomFileInfo Info; + public T Info; } } } diff --git a/src/LibHac/Fs/RomFs/RomFsBuilder.cs b/src/LibHac/Fs/RomFs/RomFsBuilder.cs index caeed1c0..0d745d31 100644 --- a/src/LibHac/Fs/RomFs/RomFsBuilder.cs +++ b/src/LibHac/Fs/RomFs/RomFsBuilder.cs @@ -18,7 +18,7 @@ namespace LibHac.Fs.RomFs private const int HeaderWithPaddingSize = 0x200; private List Sources { get; } = new List(); - private HierarchicalRomFileTable FileTable { get; } = new HierarchicalRomFileTable(); + private HierarchicalRomFileTable FileTable { get; } = new HierarchicalRomFileTable(); private long CurrentOffset { get; set; } /// diff --git a/src/LibHac/Fs/RomFs/RomFsDictionary.cs b/src/LibHac/Fs/RomFs/RomFsDictionary.cs index 0b414e1e..ef5827f1 100644 --- a/src/LibHac/Fs/RomFs/RomFsDictionary.cs +++ b/src/LibHac/Fs/RomFs/RomFsDictionary.cs @@ -5,7 +5,9 @@ using System.Runtime.InteropServices; namespace LibHac.Fs.RomFs { - internal class RomFsDictionary where T : unmanaged + // todo: Change constraint to "unmanaged" after updating to + // a newer SDK https://github.com/dotnet/csharplang/issues/1937 + internal class RomFsDictionary where T : struct { private int _count; private int _length; @@ -266,7 +268,7 @@ namespace LibHac.Fs.RomFs { var offsets = new List(_count); - int nextStructOffset = (sizeof(int) + Marshal.SizeOf()) / 4; + int nextStructOffset = (sizeof(int) + Unsafe.SizeOf()) / 4; Span data = MemoryMarshal.Cast(Entries.AsSpan()); for (int i = 0; i < Buckets.Length; i++) diff --git a/src/LibHac/Fs/RomFs/RomFsDirectory.cs b/src/LibHac/Fs/RomFs/RomFsDirectory.cs index f6faa0ec..982ae423 100644 --- a/src/LibHac/Fs/RomFs/RomFsDirectory.cs +++ b/src/LibHac/Fs/RomFs/RomFsDirectory.cs @@ -23,7 +23,7 @@ namespace LibHac.Fs.RomFs public IEnumerable Read() { FindPosition position = InitialPosition; - HierarchicalRomFileTable tab = ParentFileSystem.FileTable; + HierarchicalRomFileTable tab = ParentFileSystem.FileTable; if (Mode.HasFlag(OpenDirectoryMode.Directories)) { @@ -47,7 +47,7 @@ namespace LibHac.Fs.RomFs int count = 0; FindPosition position = InitialPosition; - HierarchicalRomFileTable tab = ParentFileSystem.FileTable; + HierarchicalRomFileTable tab = ParentFileSystem.FileTable; if (Mode.HasFlag(OpenDirectoryMode.Directories)) { diff --git a/src/LibHac/Fs/RomFs/RomFsEntries.cs b/src/LibHac/Fs/RomFs/RomFsEntries.cs index 3bdd1c56..5c12b8cd 100644 --- a/src/LibHac/Fs/RomFs/RomFsEntries.cs +++ b/src/LibHac/Fs/RomFs/RomFsEntries.cs @@ -32,7 +32,9 @@ namespace LibHac.Fs.RomFs } } - internal ref struct RomKeyValuePair where T : unmanaged + // todo: Change constraint to "unmanaged" after updating to + // a newer SDK https://github.com/dotnet/csharplang/issues/1937 + internal ref struct RomKeyValuePair where T : struct { public RomEntryKey Key; public int Offset; diff --git a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs index a74af539..ee944186 100644 --- a/src/LibHac/Fs/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/Fs/RomFs/RomFsFileSystem.cs @@ -6,7 +6,7 @@ namespace LibHac.Fs.RomFs { public RomfsHeader Header { get; } - public HierarchicalRomFileTable FileTable { get; } + public HierarchicalRomFileTable FileTable { get; } private IStorage BaseStorage { get; } public RomFsFileSystem(IStorage storage) @@ -19,7 +19,7 @@ namespace LibHac.Fs.RomFs IStorage fileHashTable = storage.Slice(Header.FileHashTableOffset, Header.FileHashTableSize); IStorage fileEntryTable = storage.Slice(Header.FileMetaTableOffset, Header.FileMetaTableSize); - FileTable = new HierarchicalRomFileTable(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable); + FileTable = new HierarchicalRomFileTable(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable); } public DirectoryEntryType GetEntryType(string path) diff --git a/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs b/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs index 6aec624a..07b8ac5e 100644 --- a/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs +++ b/src/LibHac/Fs/Save/HierarchicalSaveFileTable.cs @@ -416,6 +416,8 @@ namespace LibHac.Fs.Save } [StructLayout(LayoutKind.Sequential, Pack = 1)] + // todo: Change constraint to "unmanaged" after updating to + // a newer SDK https://github.com/dotnet/csharplang/issues/1937 private struct TableEntry where T : struct { public int NextSibling; diff --git a/src/LibHac/Fs/Save/SaveFsList.cs b/src/LibHac/Fs/Save/SaveFsList.cs index 668bb669..0bf9d428 100644 --- a/src/LibHac/Fs/Save/SaveFsList.cs +++ b/src/LibHac/Fs/Save/SaveFsList.cs @@ -6,6 +6,8 @@ using System.Runtime.InteropServices; namespace LibHac.Fs.Save { + // todo: Change constraint to "unmanaged" after updating to + // a newer SDK https://github.com/dotnet/csharplang/issues/1937 internal class SaveFsList where T : struct { private const int FreeListHeadIndex = 0; diff --git a/tests/LibHac.Tests/RomFsTests.cs b/tests/LibHac.Tests/RomFsTests.cs index 05310b2e..bce481ad 100644 --- a/tests/LibHac.Tests/RomFsTests.cs +++ b/tests/LibHac.Tests/RomFsTests.cs @@ -11,7 +11,7 @@ namespace LibHac.Tests { const string path = "/a/b"; - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); var item = new RomFileInfo { Length = 1, Offset = 1 }; table.AddFile(path, ref item); @@ -26,7 +26,7 @@ namespace LibHac.Tests { const string path = "/a/b"; - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); var originalItem = new RomFileInfo { Length = 1, Offset = 1 }; var newItem = new RomFileInfo { Length = 1, Offset = 1 }; @@ -42,7 +42,7 @@ namespace LibHac.Tests [Fact] public void AddingDirectory() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); var expectedPosition = new FindPosition { NextDirectory = -1, NextFile = -1 }; table.AddDirectory("/dir"); @@ -55,7 +55,7 @@ namespace LibHac.Tests [Fact] public void AddingEmptyPathThrows() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); var item = new RomFileInfo(); Assert.Throws(() => table.AddFile("", ref item)); @@ -64,7 +64,7 @@ namespace LibHac.Tests [Fact] public void OpeningNonexistentFileFails() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); bool success = table.TryOpenFile("/foo", out _); Assert.False(success); @@ -73,7 +73,7 @@ namespace LibHac.Tests [Fact] public void OpeningNonexistentDirectoryFails() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); bool success = table.TryOpenDirectory("/foo", out _); Assert.False(success); @@ -82,7 +82,7 @@ namespace LibHac.Tests [Fact] public void OpeningFileAsDirectoryFails() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); var fileInfo = new RomFileInfo(); table.AddFile("/file", ref fileInfo); @@ -93,7 +93,7 @@ namespace LibHac.Tests [Fact] public void OpeningDirectoryAsFileFails() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); table.AddDirectory("/dir"); bool success = table.TryOpenFile("/dir", out _); @@ -104,7 +104,7 @@ namespace LibHac.Tests public void ChildFileIteration() { const int fileCount = 10; - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); for (int i = 0; i < fileCount; i++) { @@ -134,7 +134,7 @@ namespace LibHac.Tests [Fact] public void ChildFileIterationPeek() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); var itemA = new RomFileInfo { Length = 1, Offset = 1 }; var itemB = new RomFileInfo { Length = 2, Offset = 2 }; @@ -160,7 +160,7 @@ namespace LibHac.Tests [Fact] public void AddingCousinFiles() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); var itemB1 = new RomFileInfo { Length = 1, Offset = 1 }; var itemB2 = new RomFileInfo { Length = 2, Offset = 2 }; @@ -182,7 +182,7 @@ namespace LibHac.Tests [Fact] public void AddingSiblingFiles() { - var table = new HierarchicalRomFileTable(); + var table = new HierarchicalRomFileTable(); var itemC1 = new RomFileInfo { Length = 1, Offset = 1 }; var itemC2 = new RomFileInfo { Length = 2, Offset = 2 };