mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Make the value stored by HierarchicalRomFileTable generic (#76)
* Make the value stored by HierarchicalRomFileTable generic * Don't use new language features yet
This commit is contained in:
parent
ea2572c479
commit
7099b3cdf2
9 changed files with 45 additions and 35 deletions
|
@ -6,11 +6,13 @@ namespace LibHac.Fs.RomFs
|
|||
/// <summary>
|
||||
/// Represents the file table used by the RomFS format.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value to be stored for each file entry.</typeparam>
|
||||
/// <remarks>
|
||||
/// 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 <typeparamref name="T"/>.
|
||||
/// 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, <see cref="TrimExcess"/> should be called
|
||||
/// to optimize the size of the table.
|
||||
/// </remarks>
|
||||
public class HierarchicalRomFileTable
|
||||
public class HierarchicalRomFileTable<T> where T : unmanaged
|
||||
{
|
||||
private RomFsDictionary<FileRomEntry> FileTable { get; }
|
||||
private RomFsDictionary<DirectoryRomEntry> DirectoryTable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="HierarchicalRomFileTable"/> from an existing table.
|
||||
/// Initializes a <see cref="HierarchicalRomFileTable{T}"/> from an existing table.
|
||||
/// </summary>
|
||||
/// <param name="dirHashTable"></param>
|
||||
/// <param name="dirEntryTable"></param>
|
||||
|
@ -39,17 +41,17 @@ namespace LibHac.Fs.RomFs
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="HierarchicalRomFileTable"/> that has the default initial capacity.
|
||||
/// Initializes a new <see cref="HierarchicalRomFileTable{T}"/> that has the default initial capacity.
|
||||
/// </summary>
|
||||
public HierarchicalRomFileTable() : this(0, 0) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new <see cref="HierarchicalRomFileTable"/> that has the specified initial capacity.
|
||||
/// Initializes a new <see cref="HierarchicalRomFileTable{T}"/> that has the specified initial capacity.
|
||||
/// </summary>
|
||||
/// <param name="directoryCapacity">The initial number of directories that the
|
||||
/// <see cref="HierarchicalRomFileTable"/> can contain.</param>
|
||||
/// <see cref="HierarchicalRomFileTable{T}"/> can contain.</param>
|
||||
/// <param name="fileCapacity">The initial number of files that the
|
||||
/// <see cref="HierarchicalRomFileTable"/> can contain.</param>
|
||||
/// <see cref="HierarchicalRomFileTable{T}"/> can contain.</param>
|
||||
public HierarchicalRomFileTable(int directoryCapacity, int fileCapacity)
|
||||
{
|
||||
FileTable = new RomFsDictionary<FileRomEntry>(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<FileRomEntry> keyValuePair))
|
||||
{
|
||||
|
@ -153,7 +155,7 @@ namespace LibHac.Fs.RomFs
|
|||
/// <param name="name">When this method returns, contains the file's name (Not the full path).</param>
|
||||
/// <returns><see langword="true"/> if the next file was successfully returned.
|
||||
/// <see langword="false"/> if there are no more files to enumerate.</returns>
|
||||
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
|
|||
/// </summary>
|
||||
/// <param name="path">The full path of the file to be added.</param>
|
||||
/// <param name="fileInfo">The file information to be stored.</param>
|
||||
public void AddFile(string path, ref RomFileInfo fileInfo)
|
||||
public void AddFile(string path, ref T fileInfo)
|
||||
{
|
||||
path = PathTools.Normalize(path);
|
||||
ReadOnlySpan<byte> pathBytes = Util.GetUtf8Bytes(path);
|
||||
|
@ -288,7 +290,7 @@ namespace LibHac.Fs.RomFs
|
|||
}
|
||||
}
|
||||
|
||||
private void CreateFileRecursiveInternal(ReadOnlySpan<byte> path, ref RomFileInfo fileInfo)
|
||||
private void CreateFileRecursiveInternal(ReadOnlySpan<byte> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace LibHac.Fs.RomFs
|
|||
private const int HeaderWithPaddingSize = 0x200;
|
||||
|
||||
private List<IStorage> Sources { get; } = new List<IStorage>();
|
||||
private HierarchicalRomFileTable FileTable { get; } = new HierarchicalRomFileTable();
|
||||
private HierarchicalRomFileTable<RomFileInfo> FileTable { get; } = new HierarchicalRomFileTable<RomFileInfo>();
|
||||
private long CurrentOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -5,7 +5,9 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace LibHac.Fs.RomFs
|
||||
{
|
||||
internal class RomFsDictionary<T> where T : unmanaged
|
||||
// todo: Change constraint to "unmanaged" after updating to
|
||||
// a newer SDK https://github.com/dotnet/csharplang/issues/1937
|
||||
internal class RomFsDictionary<T> where T : struct
|
||||
{
|
||||
private int _count;
|
||||
private int _length;
|
||||
|
@ -266,7 +268,7 @@ namespace LibHac.Fs.RomFs
|
|||
{
|
||||
var offsets = new List<int>(_count);
|
||||
|
||||
int nextStructOffset = (sizeof(int) + Marshal.SizeOf<T>()) / 4;
|
||||
int nextStructOffset = (sizeof(int) + Unsafe.SizeOf<T>()) / 4;
|
||||
Span<int> data = MemoryMarshal.Cast<byte, int>(Entries.AsSpan());
|
||||
|
||||
for (int i = 0; i < Buckets.Length; i++)
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace LibHac.Fs.RomFs
|
|||
public IEnumerable<DirectoryEntry> Read()
|
||||
{
|
||||
FindPosition position = InitialPosition;
|
||||
HierarchicalRomFileTable tab = ParentFileSystem.FileTable;
|
||||
HierarchicalRomFileTable<RomFileInfo> 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<RomFileInfo> tab = ParentFileSystem.FileTable;
|
||||
|
||||
if (Mode.HasFlag(OpenDirectoryMode.Directories))
|
||||
{
|
||||
|
|
|
@ -32,7 +32,9 @@ namespace LibHac.Fs.RomFs
|
|||
}
|
||||
}
|
||||
|
||||
internal ref struct RomKeyValuePair<T> 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<T> where T : struct
|
||||
{
|
||||
public RomEntryKey Key;
|
||||
public int Offset;
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace LibHac.Fs.RomFs
|
|||
{
|
||||
public RomfsHeader Header { get; }
|
||||
|
||||
public HierarchicalRomFileTable FileTable { get; }
|
||||
public HierarchicalRomFileTable<RomFileInfo> 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<RomFileInfo>(dirHashTable, dirEntryTable, fileHashTable, fileEntryTable);
|
||||
}
|
||||
|
||||
public DirectoryEntryType GetEntryType(string path)
|
||||
|
|
|
@ -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<T> where T : struct
|
||||
{
|
||||
public int NextSibling;
|
||||
|
|
|
@ -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<T> where T : struct
|
||||
{
|
||||
private const int FreeListHeadIndex = 0;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace LibHac.Tests
|
|||
{
|
||||
const string path = "/a/b";
|
||||
|
||||
var table = new HierarchicalRomFileTable();
|
||||
var table = new HierarchicalRomFileTable<RomFileInfo>();
|
||||
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<RomFileInfo>();
|
||||
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<RomFileInfo>();
|
||||
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<RomFileInfo>();
|
||||
var item = new RomFileInfo();
|
||||
|
||||
Assert.Throws<ArgumentException>(() => table.AddFile("", ref item));
|
||||
|
@ -64,7 +64,7 @@ namespace LibHac.Tests
|
|||
[Fact]
|
||||
public void OpeningNonexistentFileFails()
|
||||
{
|
||||
var table = new HierarchicalRomFileTable();
|
||||
var table = new HierarchicalRomFileTable<RomFileInfo>();
|
||||
|
||||
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<RomFileInfo>();
|
||||
|
||||
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<RomFileInfo>();
|
||||
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<RomFileInfo>();
|
||||
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<RomFileInfo>();
|
||||
|
||||
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<RomFileInfo>();
|
||||
|
||||
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<RomFileInfo>();
|
||||
|
||||
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<RomFileInfo>();
|
||||
|
||||
var itemC1 = new RomFileInfo { Length = 1, Offset = 1 };
|
||||
var itemC2 = new RomFileInfo { Length = 2, Offset = 2 };
|
||||
|
|
Loading…
Reference in a new issue