diff --git a/src/LibHac/Fs/ProgramIndexMapInfo.cs b/src/LibHac/Fs/ProgramIndexMapInfo.cs new file mode 100644 index 00000000..7e221870 --- /dev/null +++ b/src/LibHac/Fs/ProgramIndexMapInfo.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; +using LibHac.Ncm; + +namespace LibHac.Fs +{ + [StructLayout(LayoutKind.Explicit, Size = 0x20)] + public struct ProgramIndexMapInfo + { + [FieldOffset(0x00)] public ProgramId ProgramId; + [FieldOffset(0x08)] public ProgramId MainProgramId; + [FieldOffset(0x10)] public byte ProgramIndex; + } +} diff --git a/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs b/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs new file mode 100644 index 00000000..2adb6a76 --- /dev/null +++ b/src/LibHac/FsSrv/ProgramIndexMapInfoManager.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using LibHac.Fs; +using LibHac.Ncm; + +namespace LibHac.FsSrv +{ + public class ProgramIndexMapInfoManager + { + private LinkedList MapEntries { get; } = new LinkedList(); + + /// + /// Clears any existing + /// + /// The entries + /// : The operation was successful. + public Result Reset(ReadOnlySpan entries) + { + lock (MapEntries) + { + ClearImpl(); + + for (int i = 0; i < entries.Length; i++) + { + MapEntries.AddLast(entries[i]); + } + + return Result.Success; + } + } + + public void Clear() + { + lock (MapEntries) + { + ClearImpl(); + } + } + + public ProgramIndexMapInfo? 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) + { + ProgramIndexMapInfo? mainProgramMapInfo = GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId); + + if(!mainProgramMapInfo.HasValue) + return ProgramId.InvalidId; + + ProgramIndexMapInfo? requestedMapInfo = GetImpl((in ProgramIndexMapInfo x) => + x.MainProgramId == mainProgramMapInfo.Value.MainProgramId && x.ProgramIndex == programIndex); + + if (!requestedMapInfo.HasValue) + return ProgramId.InvalidId; + + return requestedMapInfo.Value.ProgramId; + } + } + + public int GetProgramCount() + { + lock (MapEntries) + { + return MapEntries.Count; + } + } + + private delegate bool EntrySelector(in ProgramIndexMapInfo candidate); + + private ProgramIndexMapInfo? GetImpl(EntrySelector selector) + { + foreach (ProgramIndexMapInfo entry in MapEntries) + { + if (selector(in entry)) + { + return entry; + } + } + + return null; + } + + private void ClearImpl() + { + MapEntries.Clear(); + } + } +} diff --git a/src/LibHac/FsSrv/ProgramRegistryServiceImpl.cs b/src/LibHac/FsSrv/ProgramRegistryServiceImpl.cs index e57fb497..90f5cfb2 100644 --- a/src/LibHac/FsSrv/ProgramRegistryServiceImpl.cs +++ b/src/LibHac/FsSrv/ProgramRegistryServiceImpl.cs @@ -8,10 +8,12 @@ namespace LibHac.FsSrv public class ProgramRegistryServiceImpl { private ProgramRegistryManager RegistryManager { get; } + private ProgramIndexMapInfoManager ProgramIndexManager { get; } public ProgramRegistryServiceImpl(FileSystemServer fsServer) { RegistryManager = new ProgramRegistryManager(fsServer); + ProgramIndexManager = new ProgramIndexMapInfoManager(); } /// @@ -67,5 +69,18 @@ namespace LibHac.FsSrv { return RegistryManager.GetProgramInfoByProgramId(out programInfo, 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) + { + return ProgramIndexManager.GetProgramId(programId, programIndex); + } } }