diff --git a/src/LibHac/FsSrv/Impl/ProgramIndexMapInfoManager.cs b/src/LibHac/FsSrv/Impl/ProgramIndexMapInfoManager.cs new file mode 100644 index 00000000..f18c9424 --- /dev/null +++ b/src/LibHac/FsSrv/Impl/ProgramIndexMapInfoManager.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using LibHac.Fs; +using LibHac.Ncm; +using LibHac.Os; +using LibHac.Util; + +namespace LibHac.FsSrv.Impl; + +/// +/// Keeps track of the program IDs and program indexes of each program in a multi-program application. +/// +/// Based on FS 13.1.0 (nnSdk 13.4.0) +public class ProgramIndexMapInfoManager : IDisposable +{ + private LinkedList _mapEntries; + private SdkMutexType _mutex; + + public ProgramIndexMapInfoManager() + { + _mapEntries = new LinkedList(); + _mutex = new SdkMutexType(); + } + + public void Dispose() + { + Clear(); + } + + /// + /// Unregisters any previously registered program index map info and registers the provided map info. + /// + /// The program map info entries to register. + /// : The operation was successful. + public Result Reset(ReadOnlySpan programIndexMapInfo) + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + ClearImpl(); + + for (int i = 0; i < programIndexMapInfo.Length; i++) + { + var entry = new ProgramIndexMapInfo + { + ProgramId = programIndexMapInfo[i].ProgramId, + MainProgramId = programIndexMapInfo[i].MainProgramId, + ProgramIndex = programIndexMapInfo[i].ProgramIndex + }; + + _mapEntries.AddLast(entry); + } + + // We skip running ClearImpl() if the allocation failed because we don't need to worry about that in C# + + return Result.Success; + + } + + /// + /// Unregisters all currently registered program index map info. + /// + public void Clear() + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + ClearImpl(); + } + + /// + /// Gets the associated with the specified program ID. + /// + /// The program ID of the map info to get. + /// If the program ID was found, the associated + /// with that ID; otherwise, . + public Optional Get(ProgramId programId) + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + return GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId); + } + + /// + /// Gets the of the program with index in the + /// multi-program app is part of. + /// + /// A program ID in the multi-program app to query. + /// The index of the program to get. + /// If the program exists, the ID of the program with the specified index, + /// otherwise + public ProgramId GetProgramId(ProgramId programId, byte programIndex) + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + Optional programIndexMapInfo = + GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId); + + if (!programIndexMapInfo.HasValue) + return ProgramId.InvalidId; + + Optional targetProgramIndexMapInfo = GetImpl((in ProgramIndexMapInfo x) => + x.MainProgramId == programIndexMapInfo.Value.MainProgramId && x.ProgramIndex == programIndex); + + if (!targetProgramIndexMapInfo.HasValue) + return ProgramId.InvalidId; + + return targetProgramIndexMapInfo.Value.ProgramId; + } + + /// + /// Gets the number of currently registered programs, + /// + /// The number of registered programs. + public int GetProgramCount() + { + using ScopedLock scopedLock = ScopedLock.Lock(ref _mutex); + + return _mapEntries.Count; + } + + private delegate bool EntrySelector(in ProgramIndexMapInfo candidate); + + private Optional GetImpl(EntrySelector selector) + { + var returnValue = new Optional(); + + foreach (ProgramIndexMapInfo entry in _mapEntries) + { + if (selector(in entry)) + { + returnValue.Set(default); + + returnValue.Value.ProgramId = entry.ProgramId; + returnValue.Value.MainProgramId = entry.MainProgramId; + returnValue.Value.ProgramIndex = entry.ProgramIndex; + + break; + } + } + + return returnValue; + } + + private void ClearImpl() + { + _mapEntries.Clear(); + } +} \ No newline at end of file diff --git a/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs b/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs deleted file mode 100644 index 2015b761..00000000 --- a/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Collections.Generic; -using LibHac.Fs; -using LibHac.Ncm; -using LibHac.Util; - -namespace LibHac.FsSrv; - -/// -/// Keeps track of the program IDs and program indexes of each program in a multi-program application. -/// -/// Based on FS 10.0.0 (nnSdk 10.4.0) -public class ProgramIndexMapInfoManager -{ - private LinkedList MapEntries { get; } = new LinkedList(); - - /// - /// Unregisters any previously registered program index map info and registers the provided map info. - /// - /// The program map info entries to register. - /// : The operation was successful. - public Result Reset(ReadOnlySpan programIndexMapInfo) - { - lock (MapEntries) - { - ClearImpl(); - - for (int i = 0; i < programIndexMapInfo.Length; i++) - { - MapEntries.AddLast(programIndexMapInfo[i]); - } - - return Result.Success; - } - } - - /// - /// Unregisters all currently registered program index map info. - /// - public void Clear() - { - lock (MapEntries) - { - ClearImpl(); - } - } - - /// - /// Gets the associated with the specified program ID. - /// - /// The program ID of the map info to get. - /// If the program ID was found, the associated - /// with that ID; otherwise, . - public Optional Get(ProgramId programId) - { - lock (MapEntries) - { - return GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId); - } - } - - /// - /// Gets the of the program with index in the - /// multi-program app is part of. - /// - /// A program ID in the multi-program app to query. - /// The index of the program to get. - /// If the program exists, the ID of the program with the specified index, - /// otherwise - public ProgramId GetProgramId(ProgramId programId, byte programIndex) - { - lock (MapEntries) - { - Optional mainProgramMapInfo = - GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId); - - if (!mainProgramMapInfo.HasValue) - return ProgramId.InvalidId; - - Optional requestedMapInfo = GetImpl((in ProgramIndexMapInfo x) => - x.MainProgramId == mainProgramMapInfo.Value.MainProgramId && x.ProgramIndex == programIndex); - - if (!requestedMapInfo.HasValue) - return ProgramId.InvalidId; - - return requestedMapInfo.Value.ProgramId; - } - } - - /// - /// Gets the number of currently registered programs, - /// - /// The number of registered programs. - public int GetProgramCount() - { - lock (MapEntries) - { - return MapEntries.Count; - } - } - - private delegate bool EntrySelector(in ProgramIndexMapInfo candidate); - - private Optional GetImpl(EntrySelector selector) - { - foreach (ProgramIndexMapInfo entry in MapEntries) - { - if (selector(in entry)) - { - return new Optional(entry); - } - } - - return new Optional(); - } - - private void ClearImpl() - { - MapEntries.Clear(); - } -} diff --git a/src/LibHac/Util/Optional.cs b/src/LibHac/Util/Optional.cs index f9d8ac7d..b73bbbef 100644 --- a/src/LibHac/Util/Optional.cs +++ b/src/LibHac/Util/Optional.cs @@ -1,4 +1,5 @@ -using System.Runtime.InteropServices; +using System; +using System.Runtime.InteropServices; using LibHac.Common; using LibHac.Diag; @@ -36,6 +37,12 @@ public struct Optional public static implicit operator Optional(in T value) => new Optional(in value); + public void Set(T value) + { + _value = value; + _hasValue = true; + } + public void Set(in T value) { _value = value; @@ -47,4 +54,4 @@ public struct Optional _hasValue = false; _value = default; } -} +} \ No newline at end of file diff --git a/tests/LibHac.Tests/FsSrv/ProgramIndexMapInfoTests.cs b/tests/LibHac.Tests/FsSrv/ProgramIndexMapInfoTests.cs index 55790e32..afa913b6 100644 --- a/tests/LibHac.Tests/FsSrv/ProgramIndexMapInfoTests.cs +++ b/tests/LibHac.Tests/FsSrv/ProgramIndexMapInfoTests.cs @@ -2,7 +2,6 @@ using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Shim; -using LibHac.FsSrv; using LibHac.FsSrv.Impl; using LibHac.Ncm; using LibHac.Util; @@ -194,4 +193,4 @@ public class ProgramIndexMapInfoTests Assert.False(manager.Get(new ProgramId(2)).HasValue); } -} +} \ No newline at end of file