Files
BinaryObjectScanner/BinaryObjectScanner/Data/StaticChecks.cs
2025-09-20 16:56:41 -04:00

182 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using BinaryObjectScanner.Interfaces;
using SabreTools.Serialization.Wrappers;
namespace BinaryObjectScanner.Data
{
internal static class StaticChecks
{
#region Public Collections
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
public static List<IContentCheck> ContentCheckClasses
{
get
{
contentCheckClasses ??= InitCheckClasses<IContentCheck>();
return contentCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IExecutableCheck<LinearExecutable> types
/// </summary>
public static List<IExecutableCheck<LinearExecutable>> LinearExecutableCheckClasses
{
get
{
linearExecutableCheckClasses ??= InitCheckClasses<IExecutableCheck<LinearExecutable>>();
return linearExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IExecutableCheck<MSDOS> types
/// </summary>
public static List<IExecutableCheck<MSDOS>> MSDOSExecutableCheckClasses
{
get
{
msdosExecutableCheckClasses ??= InitCheckClasses<IExecutableCheck<MSDOS>>();
return msdosExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IExecutableCheck<NewExecutable> types
/// </summary>
public static List<IExecutableCheck<NewExecutable>> NewExecutableCheckClasses
{
get
{
newExecutableCheckClasses ??= InitCheckClasses<IExecutableCheck<NewExecutable>>();
return newExecutableCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IPathCheck types
/// </summary>
public static List<IPathCheck> PathCheckClasses
{
get
{
pathCheckClasses ??= InitCheckClasses<IPathCheck>();
return pathCheckClasses ?? [];
}
}
/// <summary>
/// Cache for all IExecutableCheck<PortableExecutable> types
/// </summary>
public static List<IExecutableCheck<PortableExecutable>> PortableExecutableCheckClasses
{
get
{
portableExecutableCheckClasses ??= InitCheckClasses<IExecutableCheck<PortableExecutable>>();
return portableExecutableCheckClasses ?? [];
}
}
#endregion
#region Internal Instances
/// <summary>
/// Cache for all IContentCheck types
/// </summary>
private static List<IContentCheck>? contentCheckClasses;
/// <summary>
/// Cache for all IExecutableCheck<LinearExecutable> types
/// </summary>
private static List<IExecutableCheck<LinearExecutable>>? linearExecutableCheckClasses;
/// <summary>
/// Cache for all IExecutableCheck<MSDOS> types
/// </summary>
private static List<IExecutableCheck<MSDOS>>? msdosExecutableCheckClasses;
/// <summary>
/// Cache for all IExecutableCheck<NewExecutable> types
/// </summary>
private static List<IExecutableCheck<NewExecutable>>? newExecutableCheckClasses;
/// <summary>
/// Cache for all IPathCheck types
/// </summary>
private static List<IPathCheck>? pathCheckClasses;
/// <summary>
/// Cache for all IExecutableCheck<PortableExecutable> types
/// </summary>
private static List<IExecutableCheck<PortableExecutable>>? portableExecutableCheckClasses;
#endregion
#region Helpers
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static List<T>? InitCheckClasses<T>()
=> InitCheckClasses<T>(Assembly.GetExecutingAssembly()) ?? [];
/// <summary>
/// Initialize all implementations of a type
/// </summary>
private static List<T> InitCheckClasses<T>(Assembly assembly)
{
// Get information from the type param
string? interfaceName = typeof(T).FullName;
if (interfaceName == null)
return [];
// If not all types can be loaded, use the ones that could be
Type?[] assemblyTypes;
try
{
assemblyTypes = assembly.GetTypes();
}
catch (ReflectionTypeLoadException rtle)
{
assemblyTypes = rtle.Types ?? [];
}
// If no assembly types are found
if (assemblyTypes.Length == 0)
return [];
// Loop through all types
List<T> classTypes = [];
foreach (Type? type in assemblyTypes)
{
// Skip invalid types
if (type == null)
continue;
// If the type isn't a class
if (!type.IsClass)
continue;
// If the type isn't a class or doesn't implement the interface
var interfaces = Array.ConvertAll(type.GetInterfaces(), i => i.FullName);
if (!Array.Exists(interfaces, i => i == interfaceName))
continue;
// Try to create a concrete instance of the type
var instance = (T?)Activator.CreateInstance(type);
if (instance != null)
classTypes.Add(instance);
}
return classTypes;
}
#endregion
}
}