diff --git a/src/LibHac/IO/RomFs/HierarchicalRomFileTable.cs b/src/LibHac/IO/RomFs/HierarchicalRomFileTable.cs index 05d91937..d47549d3 100644 --- a/src/LibHac/IO/RomFs/HierarchicalRomFileTable.cs +++ b/src/LibHac/IO/RomFs/HierarchicalRomFileTable.cs @@ -55,7 +55,7 @@ namespace LibHac.IO.RomFs return FileTable.GetEntryData().ToArray(); } - public bool OpenFile(string path, out RomFileInfo fileInfo) + public bool TryOpenFile(string path, out RomFileInfo fileInfo) { FindFileRecursive(GetUtf8Bytes(path), out RomEntryKey key); @@ -69,9 +69,9 @@ namespace LibHac.IO.RomFs return false; } - public bool OpenFile(int offset, out RomFileInfo fileInfo) + public bool TryOpenFile(int fileId, out RomFileInfo fileInfo) { - if (FileTable.TryGetValue(offset, out RomKeyValuePair keyValuePair)) + if (FileTable.TryGetValue(fileId, out RomKeyValuePair keyValuePair)) { fileInfo = keyValuePair.Value.Info; return true; @@ -81,7 +81,7 @@ namespace LibHac.IO.RomFs return false; } - public bool OpenDirectory(string path, out FindPosition position) + public bool TryOpenDirectory(string path, out FindPosition position) { FindDirectoryRecursive(GetUtf8Bytes(path), out RomEntryKey key); @@ -95,9 +95,9 @@ namespace LibHac.IO.RomFs return false; } - public bool OpenDirectory(int offset, out FindPosition position) + public bool TryOpenDirectory(int directoryId, out FindPosition position) { - if (DirectoryTable.TryGetValue(offset, out RomKeyValuePair keyValuePair)) + if (DirectoryTable.TryGetValue(directoryId, out RomKeyValuePair keyValuePair)) { position = keyValuePair.Value.Pos; return true; @@ -107,11 +107,6 @@ namespace LibHac.IO.RomFs return false; } - private static ReadOnlySpan GetUtf8Bytes(string value) - { - return Encoding.UTF8.GetBytes(value).AsSpan(); - } - public bool FindNextFile(ref FindPosition position, out RomFileInfo info, out string name) { if (position.NextFile == -1) @@ -145,6 +140,26 @@ namespace LibHac.IO.RomFs return true; } + public void CreateFile(string path, ref RomFileInfo fileInfo) + { + path = PathTools.Normalize(path); + ReadOnlySpan pathBytes = GetUtf8Bytes(path); + + CreateFileRecursiveInternal(pathBytes, ref fileInfo); + } + + public void CreateDirectory(string path) + { + path = PathTools.Normalize(path); + + CreateDirectoryRecursive(GetUtf8Bytes(path)); + } + + private static ReadOnlySpan GetUtf8Bytes(string value) + { + return Encoding.UTF8.GetBytes(value).AsSpan(); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static string GetUtf8String(ReadOnlySpan value) { @@ -163,22 +178,7 @@ namespace LibHac.IO.RomFs entry.Pos.NextDirectory = -1; entry.Pos.NextFile = -1; - DirectoryTable.Insert(ref key, ref entry); - } - - public void CreateFile(string path, ref RomFileInfo fileInfo) - { - path = PathTools.Normalize(path); - ReadOnlySpan pathBytes = GetUtf8Bytes(path); - - CreateFileRecursiveInternal(pathBytes, ref fileInfo); - } - - public void CreateDirectory(string path) - { - path = PathTools.Normalize(path); - - CreateDirectoryRecursive(GetUtf8Bytes(path)); + DirectoryTable.Add(ref key, ref entry); } private void CreateDirectoryRecursive(ReadOnlySpan path) @@ -193,7 +193,7 @@ namespace LibHac.IO.RomFs int offset = DirectoryTable.GetOffsetFromKey(ref key); if (offset < 0) { - ref DirectoryRomEntry entry = ref DirectoryTable.Insert(ref key, out offset, out _); + ref DirectoryRomEntry entry = ref DirectoryTable.AddOrGet(ref key, out offset, out _, out _); entry.NextSibling = -1; entry.Pos.NextDirectory = -1; entry.Pos.NextFile = -1; @@ -235,7 +235,7 @@ namespace LibHac.IO.RomFs int offset = DirectoryTable.GetOffsetFromKey(ref key); if (offset < 0) { - ref DirectoryRomEntry entry = ref DirectoryTable.Insert(ref key, out offset, out _); + ref DirectoryRomEntry entry = ref DirectoryTable.AddOrGet(ref key, out offset, out _, out _); entry.NextSibling = -1; entry.Pos.NextDirectory = -1; entry.Pos.NextFile = -1; @@ -265,7 +265,7 @@ namespace LibHac.IO.RomFs } { - ref FileRomEntry entry = ref FileTable.Insert(ref key, out int offset, out _); + ref FileRomEntry entry = ref FileTable.AddOrGet(ref key, out int offset, out _, out _); entry.NextSibling = -1; entry.Info = fileInfo; diff --git a/src/LibHac/IO/RomFs/RomFsDictionary.cs b/src/LibHac/IO/RomFs/RomFsDictionary.cs index 2a2b49c1..18b80dd9 100644 --- a/src/LibHac/IO/RomFs/RomFsDictionary.cs +++ b/src/LibHac/IO/RomFs/RomFsDictionary.cs @@ -42,18 +42,7 @@ namespace LibHac.IO.RomFs public bool TryGetValue(ref RomEntryKey key, out RomKeyValuePair value) { - int i = FindEntry(ref key); - - if (i >= 0) - { - ref RomFsEntry entry = ref GetEntryReference(i); - - value = new RomKeyValuePair { Key = key, Value = entry.Value, Offset = i }; - return true; - } - - value = default; - return false; + return TryGetValue(GetOffsetFromKey(ref key), out value); } public bool TryGetValue(int offset, out RomKeyValuePair value) @@ -71,78 +60,75 @@ namespace LibHac.IO.RomFs value.Key.Name = name; value.Value = entry.Value; value.Key.Parent = entry.Parent; + value.Offset = offset; return true; } - public bool TrySetValue(ref RomEntryKey key, ref T value) + public ref T GetValueReference(int offset) { - int i = FindEntry(ref key); - if (i < 0) return false; - - ref RomFsEntry entry = ref GetEntryReference(i); - entry.Value = value; - - return true; - } - - public ref T GetValue(int offset, out Span name) - { - ref RomFsEntry entry = ref GetEntryReference(offset, out name); - + ref RomFsEntry entry = ref MemoryMarshal.Cast(Entries.AsSpan(offset))[0]; return ref entry.Value; } - public bool ContainsKey(ref RomEntryKey key) => FindEntry(ref key) >= 0; - - public int Insert(ref RomEntryKey key, ref T value) + public ref T GetValueReference(int offset, out Span name) { - if (ContainsKey(ref key)) + ref RomFsEntry entry = ref MemoryMarshal.Cast(Entries.AsSpan(offset))[0]; + + name = Entries.AsSpan(offset + _sizeOfEntry, entry.KeyLength); + return ref entry.Value; + } + + public bool ContainsKey(ref RomEntryKey key) => GetOffsetFromKey(ref key) >= 0; + + public int Add(ref RomEntryKey key, ref T value) + { + ref T entry = ref AddOrGet(ref key, out int offset, out bool alreadyExists, out _); + + if (alreadyExists) { throw new ArgumentException("Key already exists in dictionary."); } - uint hashCode = key.GetRomHashCode(); + entry = value; - int bucket = (int)(hashCode % Buckets.Length); - int newOffset = FindOffsetForInsert(key.Name.Length); - - ref RomFsEntry entry = ref GetEntryReference(newOffset, out Span name, key.Name.Length); - - entry.Next = Buckets[bucket]; - entry.Parent = key.Parent; - entry.KeyLength = key.Name.Length; - entry.Value = value; - - key.Name.CopyTo(name); - - Buckets[bucket] = newOffset; - _count++; - return newOffset; + return offset; } - public ref T Insert(ref RomEntryKey key, out int offset, out Span name) + public ref T AddOrGet(ref RomEntryKey key, out int offset, out bool alreadyExists, out Span name) { - uint hashCode = key.GetRomHashCode(); + int oldOffset = GetOffsetFromKey(ref key); - int bucket = (int)(hashCode % Buckets.Length); - int newOffset = FindOffsetForInsert(key.Name.Length); + if (oldOffset >= 0) + { + alreadyExists = true; + offset = oldOffset; - ref RomFsEntry entry = ref GetEntryReference(newOffset, out name, key.Name.Length); + ref RomFsEntry entry = ref GetEntryReference(oldOffset, out name); + return ref entry.Value; + } + else + { + int newOffset = CreateNewEntry(key.Name.Length); + alreadyExists = false; + offset = newOffset; - entry.KeyLength = key.Name.Length; + ref RomFsEntry entry = ref GetEntryReference(newOffset, out name, key.Name.Length); - entry.Next = Buckets[bucket]; - entry.Parent = key.Parent; - key.Name.CopyTo(name); + entry.Parent = key.Parent; + entry.KeyLength = key.Name.Length; + key.Name.CopyTo(name); - Buckets[bucket] = newOffset; - _count++; + int bucket = (int)(key.GetRomHashCode() % Buckets.Length); - offset = newOffset; - return ref entry.Value; + entry.Next = Buckets[bucket]; + Buckets[bucket] = newOffset; + _count++; + + return ref entry.Value; + } } - private int FindOffsetForInsert(int nameLength) + private int CreateNewEntry(int nameLength) { int bytesNeeded = Util.AlignUp(_sizeOfEntry + nameLength, 4); @@ -157,27 +143,6 @@ namespace LibHac.IO.RomFs return offset; } - private int FindEntry(ref RomEntryKey key) - { - uint hashCode = key.GetRomHashCode(); - int index = (int)(hashCode % Buckets.Length); - int i = Buckets[index]; - - while (i != -1) - { - ref RomFsEntry entry = ref GetEntryReference(i, out Span name); - - if (key.Parent == entry.Parent && key.Name.SequenceEqual(name)) - { - break; - } - - i = entry.Next; - } - - return i; - } - public int GetOffsetFromKey(ref RomEntryKey key) { uint hashCode = key.GetRomHashCode(); @@ -225,7 +190,7 @@ namespace LibHac.IO.RomFs } } - public int CountEntries() + private int CountEntries() { int count = 0; int nextStructOffset = (sizeof(int) + Marshal.SizeOf()) / 4; @@ -266,20 +231,6 @@ namespace LibHac.IO.RomFs Buckets = newBuckets; } - public ref T GetValueReference(int offset) - { - ref RomFsEntry entry = ref MemoryMarshal.Cast(Entries.AsSpan(offset))[0]; - return ref entry.Value; - } - - public ref T GetValueReference(int offset, out Span name) - { - ref RomFsEntry entry = ref MemoryMarshal.Cast(Entries.AsSpan(offset))[0]; - - name = Entries.AsSpan(offset + _sizeOfEntry, entry.KeyLength); - return ref entry.Value; - } - private ref RomFsEntry GetEntryReference(int offset) { return ref MemoryMarshal.Cast(Entries.AsSpan(offset))[0]; diff --git a/src/LibHac/IO/RomFs/RomFsFileSystem.cs b/src/LibHac/IO/RomFs/RomFsFileSystem.cs index 2ef69c1d..54d5598c 100644 --- a/src/LibHac/IO/RomFs/RomFsFileSystem.cs +++ b/src/LibHac/IO/RomFs/RomFsFileSystem.cs @@ -43,7 +43,7 @@ namespace LibHac.IO.RomFs { path = PathTools.Normalize(path); - if (!FileTable.OpenDirectory(path, out FindPosition position)) + if (!FileTable.TryOpenDirectory(path, out FindPosition position)) { throw new DirectoryNotFoundException(); } @@ -55,7 +55,7 @@ namespace LibHac.IO.RomFs { path = PathTools.Normalize(path); - if (!FileTable.OpenFile(path, out RomFileInfo info)) + if (!FileTable.TryOpenFile(path, out RomFileInfo info)) { throw new FileNotFoundException(); } @@ -72,14 +72,14 @@ namespace LibHac.IO.RomFs { path = PathTools.Normalize(path); - return FileTable.OpenDirectory(path, out FindPosition _); + return FileTable.TryOpenDirectory(path, out FindPosition _); } public bool FileExists(string path) { path = PathTools.Normalize(path); - return FileTable.OpenFile(path, out RomFileInfo _); + return FileTable.TryOpenFile(path, out RomFileInfo _); } public IStorage GetBaseStorage()