UI/Library/GameEntry.cs
namespace sGBA;
public sealed class GameEntry( string path, string displayTitle, string region,
string gameCode, string noIntroName, BaseFileSystem fileSystem )
{
public string Path { get; } = path;
public string DisplayTitle { get; } = displayTitle;
public string Region { get; } = region;
public string GameCode { get; } = gameCode;
public string NoIntroName { get; } = noIntroName;
public BaseFileSystem FileSystem { get; } = fileSystem;
public static List<GameEntry> Discover()
{
List<GameEntry> entries = [];
CollectFrom( Sandbox.FileSystem.Mounted, entries );
CollectFrom( Sandbox.FileSystem.Data, entries );
entries.Sort( ( a, b ) => string.Compare( a.DisplayTitle, b.DisplayTitle, StringComparison.OrdinalIgnoreCase ) );
return entries;
}
public static HashSet<string> GetInstalledPaths()
{
var paths = new HashSet<string>( StringComparer.OrdinalIgnoreCase );
CollectPathsFrom( Sandbox.FileSystem.Mounted, paths );
CollectPathsFrom( Sandbox.FileSystem.Data, paths );
return paths;
}
private static void CollectFrom( BaseFileSystem fileSystem, List<GameEntry> entries )
{
IEnumerable<string> found;
try { found = fileSystem.FindFile( "roms", "*.gba" ) ?? []; }
catch { return; }
foreach ( string fileName in found )
{
GameEntry entry = BuildEntry( fileSystem, $"roms/{fileName}", fileName );
if ( entry is not null )
entries.Add( entry );
}
}
private static void CollectPathsFrom( BaseFileSystem fileSystem, HashSet<string> paths )
{
try
{
foreach ( var fileName in fileSystem.FindFile( "roms", "*.gba" ) ?? [] )
paths.Add( $"roms/{fileName}" );
}
catch
{
}
}
private static GameEntry BuildEntry( BaseFileSystem fileSystem, string fullPath, string fileName )
{
string baseName = System.IO.Path.GetFileNameWithoutExtension( fileName );
(string displayTitle, string region) = ParseNoIntroName( baseName );
string gameCode = ReadGameCode( fileSystem, fullPath );
return new GameEntry( fullPath, displayTitle, region, gameCode, baseName, fileSystem );
}
private static (string DisplayTitle, string Region) ParseNoIntroName( string baseName )
{
int parenOpen = baseName.IndexOf( '(' );
if ( parenOpen <= 0 )
return (baseName, string.Empty);
string displayTitle = baseName[..parenOpen].TrimEnd();
int parenClose = baseName.IndexOf( ')', parenOpen );
string region = parenClose > parenOpen ? baseName[(parenOpen + 1)..parenClose] : string.Empty;
return (displayTitle, region);
}
private static string ReadGameCode( BaseFileSystem fileSystem, string path )
{
try
{
using System.IO.Stream stream = fileSystem.OpenRead( path );
if ( stream.Length < 0xB0 )
return string.Empty;
byte[] header = new byte[0xB0];
stream.ReadExactly( header, 0, 0xB0 );
return System.Text.Encoding.ASCII.GetString( header, 0xAC, 4 ).TrimEnd( '\0' );
}
catch
{
return string.Empty;
}
}
}