Add project files.

This commit is contained in:
Cj 2024-06-11 19:18:48 -04:00
parent 8ee03dd905
commit f76ba2f091
13 changed files with 1025 additions and 0 deletions

25
AssemblyRemapper.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34728.123
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AssemblyRemapper", "AssemblyRemapper\AssemblyRemapper.csproj", "{84BF5F6E-9EEC-4B08-BE72-9F419A369124}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{84BF5F6E-9EEC-4B08-BE72-9F419A369124}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{84BF5F6E-9EEC-4B08-BE72-9F419A369124}.Debug|Any CPU.Build.0 = Debug|Any CPU
{84BF5F6E-9EEC-4B08-BE72-9F419A369124}.Release|Any CPU.ActiveCfg = Release|Any CPU
{84BF5F6E-9EEC-4B08-BE72-9F419A369124}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C2C7C51D-6773-404D-B51D-BC279AC9B923}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,41 @@
using AssemblyRemapper.Reflection;
using AssemblyRemapper.Utils;
namespace AssemblyRemapper.Commands
{
internal class CommandProcessor
{
public CommandProcessor()
{ }
public void CommandLoop()
{
ShowStartText();
while (true)
{
var input = Console.ReadLine();
ProcessCommand(input);
}
}
private void ProcessCommand(string command)
{
if (command == "remap" || command == "Remap")
{
var remapper = new Remapper();
remapper.InitializeRemap();
}
}
private void ShowStartText()
{
Logger.Log($"-----------------------------------------------------------------", ConsoleColor.Green);
Logger.Log($"Cj's Assembly Tool", ConsoleColor.Green);
Logger.Log($"Version 0.1.0", ConsoleColor.Green);
Logger.Log($"Available Commands: `remap` `help`", ConsoleColor.Green);
Logger.Log($"-----------------------------------------------------------------", ConsoleColor.Green);
}
}
}

View File

@ -0,0 +1,65 @@
namespace AssemblyRemapper.Models;
/// <summary>
/// Remap config
/// </summary>
internal class AppSettings
{
public bool Debug { get; set; }
public bool SilentMode { get; set; }
public bool ScoringMode { get; set; }
public bool Publicize { get; set; }
public bool Unseal { get; set; }
public string AssemblyPath { get; set; }
public string OutputPath { get; set; }
public HashSet<Remap> Remaps { get; set; } = [];
}
/// <summary>
/// Object to store linq statements in inside of json to search and remap classes
/// </summary>
internal class Remap
{
public string NewTypeName { get; set; } = string.Empty;
public string OldTypeName { get; set; } = string.Empty;
public bool UseDirectRename { get; set; }
public RemapSearchParams SearchParams { get; set; } = new();
}
/// <summary>
/// Search filters to find types and remap them
/// </summary>
internal class RemapSearchParams
{
public bool? IsPublic { get; set; } = null;
public bool? IsAbstract { get; set; } = null;
public bool? IsInterface { get; set; } = null;
public bool? IsEnum { get; set; } = null;
public bool? IsNested { get; set; } = null;
public string? ParentName { get; set; } = null;
public bool? IsSealed { get; set; } = null;
public bool? HasAttribute { get; set; } = null;
public bool? IsDerived { get; set; } = null;
public string? BaseClassName { get; set; } = null;
public bool? IsGeneric { get; set; } = null;
public HashSet<string> MethodNamesToMatch { get; set; } = [];
public HashSet<string> MethodNamesToIgnore { get; set; } = [];
public HashSet<string> FieldNamesToMatch { get; set; } = [];
public HashSet<string> FieldNamesToIgnore { get; set; } = [];
public HashSet<string> PropertyNamesToMatch { get; set; } = [];
public HashSet<string> PropertyNamesToIgnore { get; set; } = [];
public HashSet<string> NestedTypesToMatch { get; set; } = [];
public HashSet<string> NestedTypesToIgnore { get; set; } = [];
public RemapSearchParams()
{
}
}

View File

@ -0,0 +1,10 @@
namespace AssemblyRemapper.Models;
internal enum ELogLevel
{
None = 0,
Success = 1,
Warn = 2,
Error = 3,
Full = 4,
}

View File

@ -0,0 +1,9 @@
namespace AssemblyRemapper.Models;
internal enum EMatchResult
{
NoMatch = -1,
Disabled = 0,
SearchedNoResult = 1,
Match = 2,
}

View File

@ -0,0 +1,43 @@
using AssemblyRemapper.Reflection;
using Mono.Cecil;
namespace AssemblyRemapper.Models;
internal class ScoringModel
{
public int Score { get; set; } = 0;
public string ProposedNewName { get; set; }
public TypeDefinition Definition { get; set; }
public ScoringModel()
{
}
}
internal static class ScoringModelExtensions
{
public static void AddModelToResult(this ScoringModel model)
{
try
{
if (Remapper.ScoringModels.TryGetValue(model.ProposedNewName, out HashSet<ScoringModel> modelHashset))
{
modelHashset.Add(model);
return;
}
var newHash = new HashSet<ScoringModel>
{
model
};
Remapper.ScoringModels.Add(model.ProposedNewName, newHash);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}

View File

@ -0,0 +1,13 @@
using AssemblyRemapper.Commands;
namespace AssemblyRemapper;
public static class Program
{
public static void Main(string[] args)
{
var cmd = new CommandProcessor();
cmd.CommandLoop();
}
}

View File

@ -0,0 +1,306 @@
using AssemblyRemapper.Models;
using AssemblyRemapper.Utils;
using Mono.Cecil;
namespace AssemblyRemapper.Reflection;
internal class Remapper
{
public static Dictionary<string, HashSet<ScoringModel>> ScoringModels { get; set; } = [];
public void InitializeRemap()
{
// Make sure any previous results are cleared just incase
ScoringModels.Clear();
DisplayBasicModuleInformation();
StartRemap();
}
private void DisplayBasicModuleInformation()
{
Logger.Log($"Module contains {DataProvider.ModuleDefinition.Types.Count} Types");
Logger.Log($"Starting remap...");
Logger.Log($"Publicize: {DataProvider.AppSettings.Publicize}");
Logger.Log($"Unseal: {DataProvider.AppSettings.Unseal}");
}
private void StartRemap()
{
foreach (var remap in DataProvider.AppSettings.Remaps)
{
Logger.Log("-----------------------------------------------");
Logger.Log($"Trying to remap {remap.NewTypeName}...");
HandleMapping(remap);
}
ChooseBestMatches();
if (DataProvider.AppSettings.ScoringMode) { return; }
// Dont publicize and unseal until after the remapping so we can use those as search parameters
HandlePublicize();
HandleUnseal();
// We are done, write the assembly
WriteAssembly();
}
private void HandleMapping(Remap mapping)
{
string newName = mapping.NewTypeName;
string oldName = mapping?.OldTypeName ?? string.Empty;
bool useDirectRename = mapping.UseDirectRename;
foreach (var type in DataProvider.ModuleDefinition.Types)
{
// Handle Direct Remaps by strict naming first bypasses everything else
if (useDirectRename)
{
HandleByDirectName(oldName, newName, type);
continue;
}
ScoreType(type, mapping);
}
}
private void HandlePublicize()
{
if (!DataProvider.AppSettings.Publicize) { return; }
Logger.Log("Starting publicization...");
foreach (var type in DataProvider.ModuleDefinition.Types)
{
if (type.IsNotPublic) { type.IsPublic = true; }
// We only want to do methods and properties
if (type.HasMethods)
{
foreach (var method in type.Methods)
{
method.IsPublic = true;
}
}
if (type.HasProperties)
{
foreach (var property in type.Properties)
{
if (property.SetMethod != null)
{
property.SetMethod.IsPublic = true;
}
if (property.GetMethod != null)
{
property.GetMethod.IsPublic = true;
}
}
}
}
}
private void HandleUnseal()
{
if (!DataProvider.AppSettings.Unseal) { return; }
Logger.Log("Starting unseal...");
foreach (var type in DataProvider.ModuleDefinition.Types)
{
if (type.IsSealed) { type.IsSealed = false; }
}
}
private void HandleByDirectName(string oldName, string newName, TypeDefinition type)
{
if (type.Name != oldName) { return; }
Logger.Log($"Renaming directly...");
type.Name = newName;
RenameService.RenameAllFields(oldName, newName, DataProvider.ModuleDefinition.Types);
RenameService.RenameAllProperties(oldName, newName, DataProvider.ModuleDefinition.Types);
Logger.Log($"Renamed {oldName} to {newName}");
Logger.Log("-----------------------------------------------");
}
private void ScoreType(TypeDefinition type, Remap remap, string parentTypeName = "")
{
foreach (var nestedType in type.NestedTypes)
{
ScoreType(nestedType, remap, type.Name);
}
var score = new ScoringModel
{
Definition = type,
ProposedNewName = remap.NewTypeName,
};
if (type.MatchIsAbstract(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
/*
if (type.MatchIsEnum(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchIsNested(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
type.MatchIsSealed(remap.SearchParams, score);
if (type.MatchIsSealed(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchIsDerived(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchIsInterface(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchIsGeneric(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchIsPublic(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchHasAttribute(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchMethods(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchFields(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchProperties(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
if (type.MatchNestedTypes(remap.SearchParams, score) == EMatchResult.NoMatch)
{
return;
}
*/
ScoringModelExtensions.AddModelToResult(score);
}
private void ChooseBestMatches()
{
foreach (var remap in ScoringModels)
{
ChooseBestMatch(remap.Value, true);
}
}
private void ChooseBestMatch(HashSet<ScoringModel> scores, bool isBest = false)
{
if (ScoringModels.Count == 0)
{
return;
}
var highestScore = scores.OrderByDescending(model => model.Score).FirstOrDefault();
var secondScore = scores.OrderByDescending(model => model.Score).Skip(1).FirstOrDefault();
if (highestScore is null || secondScore is null) { return; }
var potentialText = isBest
? "Best potential"
: "Next potential";
if (highestScore.Score <= 0) { return; }
Logger.Log("-----------------------------------------------");
Logger.Log($"Found {scores.Count} possible matches");
Logger.Log($"Scored: {highestScore.Score} points");
Logger.Log($"Next Best: {secondScore.Score} points");
Logger.Log($"{potentialText} match is `{highestScore.Definition.Name}` for `{highestScore.ProposedNewName}`");
if (DataProvider.AppSettings.ScoringMode)
{
Logger.Log("Show next result? (y/n)");
var answer = Console.ReadLine();
if (answer == "yes" || answer == "y")
{
scores.Remove(highestScore);
ChooseBestMatch(scores);
}
Logger.Log("-----------------------------------------------");
return;
}
var anwser = "";
if (!DataProvider.AppSettings.SilentMode)
{
Logger.Log($"Should we continue? (y/n)");
anwser = Console.ReadLine();
}
if (anwser == "yes" || anwser == "y" || DataProvider.AppSettings.SilentMode)
{
var oldName = highestScore.Definition.Name;
highestScore.Definition.Name = highestScore.ProposedNewName;
RenameService.RenameAllFields(oldName, highestScore.Definition.Name, DataProvider.ModuleDefinition.Types);
RenameService.RenameAllProperties(oldName, highestScore.Definition.Name, DataProvider.ModuleDefinition.Types);
Logger.Log($"Remapped {oldName} to `{highestScore.Definition.Name}`");
Logger.Log("-----------------------------------------------");
return;
}
scores.Remove(highestScore);
ChooseBestMatch(scores);
}
private void WriteAssembly()
{
var filename = Path.GetFileNameWithoutExtension(DataProvider.AppSettings.AssemblyPath);
var strippedPath = Path.GetDirectoryName(filename);
filename = $"{filename}-Remapped.dll";
var remappedPath = Path.Combine(strippedPath, filename);
DataProvider.AssemblyDefinition.Write(remappedPath);
Logger.Log("-----------------------------------------------");
Logger.Log($"Complete: Assembly written to `{remappedPath}`");
Logger.Log("-----------------------------------------------");
}
}

View File

@ -0,0 +1,72 @@
using AssemblyRemapper.Utils;
using Mono.Collections.Generic;
namespace AssemblyRemapper.Reflection;
internal static class RenameService
{
public static void RenameAllFields(
string oldName,
string newName,
Collection<Mono.Cecil.TypeDefinition> types)
{
foreach (var type in types)
{
int fieldCount = 0;
foreach (var field in type.Fields)
{
if (field.FieldType.ToString() == newName)
{
Logger.Log($"Renaming Field: `{field.Name}` on Type `{type}`");
field.Name = GetNewFieldName(newName, field.IsPrivate, fieldCount);
fieldCount++;
}
}
if (type.HasNestedTypes)
{
foreach (var _ in type.NestedTypes)
{
RenameAllFields(oldName, newName, type.NestedTypes);
}
}
}
}
public static void RenameAllProperties(
string oldName,
string newName,
Collection<Mono.Cecil.TypeDefinition> types)
{
foreach (var type in types)
{
int propertyCount = 0;
foreach (var property in type.Properties)
{
if (property.PropertyType.ToString() == newName)
{
Logger.Log($"Renaming Property: `{property.Name}` on Type `{type}`");
property.Name = propertyCount > 0 ? $"{newName}_{propertyCount}" : newName;
}
}
if (type.HasNestedTypes)
{
foreach (var _ in type.NestedTypes)
{
RenameAllProperties(oldName, newName, type.NestedTypes);
}
}
}
}
private static string GetNewFieldName(string TypeName, bool isPrivate, int fieldCount = 0)
{
var discard = isPrivate ? "_" : "";
string newFieldCount = fieldCount > 0 ? $"_{fieldCount}" : string.Empty;
return $"{discard}{char.ToLower(TypeName[0])}{TypeName[1..]}{newFieldCount}";
}
}

View File

@ -0,0 +1,326 @@
using AssemblyRemapper.Models;
using AssemblyRemapper.Utils;
using Mono.Cecil;
using Mono.Cecil.Rocks;
namespace AssemblyRemapper.Reflection;
internal static class SearchProvider
{
public static int MatchCount { get; private set; }
public static EMatchResult MatchIsAbstract(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.IsAbstract is null)
{
return EMatchResult.Disabled;
}
// Interfaces cannot be abstract, and abstract cannot be static
if (type.IsInterface || type.GetStaticConstructor() != null)
{
Logger.Log($"Searching for an abstract type, skipping interface or static");
return EMatchResult.NoMatch;
}
if (type.IsAbstract != parms.IsAbstract)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : IsAbstract");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` IsAbstract does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsEnum(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.IsEnum is null)
{
return EMatchResult.Disabled;
}
if (type.IsEnum == parms.IsEnum)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : IsEnum");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` IsEnum does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsNested(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.IsNested is null)
{
return EMatchResult.Disabled;
}
if (type.IsNested == parms.IsNested)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : IsNested");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` IsNested does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsSealed(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.IsSealed is null)
{
return EMatchResult.Disabled;
}
if (type.IsSealed == parms.IsSealed)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : IsSealed");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` IsSealed does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsDerived(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.IsDerived is null)
{
return EMatchResult.Disabled;
}
if (type.BaseType != null && (bool)parms.IsDerived)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : IsDerived");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` IsDerived does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsInterface(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.IsInterface is null)
{
return EMatchResult.Disabled;
}
// Interfaces cannot be a class
if (type.IsClass)
{
return EMatchResult.NoMatch;
}
if (type.IsInterface != parms.IsInterface)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : IsInterface");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` IsInterface does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsGeneric(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.IsGeneric is null)
{
return EMatchResult.Disabled;
}
if (type.HasGenericParameters == parms.IsGeneric)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : IsGeneric");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` IsGeneric does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchIsPublic(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.IsPublic is null)
{
return EMatchResult.Disabled;
}
if (type.IsPublic == parms.IsPublic)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : IsPublic");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` IsPublic does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchHasAttribute(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
if (parms.HasAttribute is null)
{
return EMatchResult.Disabled;
}
if (type.HasCustomAttributes == parms.HasAttribute)
{
score.Score += 1;
Logger.Log($"Matched `{type.Name}` on search `{score.ProposedNewName}` : HasAttribute");
return EMatchResult.Match;
}
Logger.Log($"Skipping `{type.Name}` on search `{score.ProposedNewName}` HasAttribute does not match.");
return EMatchResult.NoMatch;
}
public static EMatchResult MatchMethods(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
// Ignore types that dont have methods when we are looking for them, and ignore types that
// have methods while we're not looking for them
if ((type.HasMethods is true && parms.MethodNamesToMatch.Count == 0) || (type.HasMethods is false && parms.MethodNamesToMatch.Count > 0))
{
return EMatchResult.NoMatch;
}
// `*` is the wildcard to ignore all methods that exist on types
if (parms.MethodNamesToIgnore.Contains("*"))
{
return EMatchResult.NoMatch;
}
int matchCount = 0;
foreach (var method in type.Methods)
{
if (parms.MethodNamesToIgnore.Contains(method.Name))
{
// Type contains blacklisted method
return EMatchResult.NoMatch;
}
if (parms.MethodNamesToMatch.Contains(method.Name))
{
matchCount++;
score.Score += 2;
}
}
return matchCount > 0 ? EMatchResult.Match : EMatchResult.NoMatch;
}
public static EMatchResult MatchFields(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
// Ignore types that dont have fields when we are looking for them, and ignore types that
// have fields while we're not looking for them
if ((type.HasFields is true && parms.FieldNamesToMatch.Count == 0) || (type.HasFields is false && parms.FieldNamesToMatch.Count > 0))
{
return EMatchResult.NoMatch;
}
// `*` is the wildcard to ignore all fields that exist on types
if (parms.FieldNamesToIgnore.Contains("*"))
{
return EMatchResult.NoMatch;
}
int matchCount = 0;
foreach (var field in type.Fields)
{
if (parms.FieldNamesToIgnore.Contains(field.Name))
{
// Type contains blacklisted field
return EMatchResult.NoMatch;
}
if (parms.FieldNamesToMatch.Contains(field.Name))
{
matchCount++;
score.Score += 2;
}
}
return matchCount > 0 ? EMatchResult.Match : EMatchResult.NoMatch;
}
public static EMatchResult MatchProperties(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
// Ignore types that dont have properties when we are looking for them, and ignore types
// that have properties while we're not looking for them
if ((type.HasProperties is true && parms.PropertyNamesToMatch.Count == 0) || (type.HasProperties is false && parms.PropertyNamesToMatch.Count > 0))
{
return EMatchResult.NoMatch;
}
// `*` is the wildcard to ignore all properties that exist on types
if (parms.PropertyNamesToIgnore.Contains("*"))
{
return EMatchResult.NoMatch;
}
int matchCount = 0;
foreach (var property in type.Properties)
{
if (parms.PropertyNamesToIgnore.Contains(property.Name))
{
// Type contains blacklisted property
return EMatchResult.NoMatch;
}
if (parms.PropertyNamesToMatch.Contains(property.Name))
{
matchCount++;
score.Score += 2;
}
}
return matchCount > 0 ? EMatchResult.Match : EMatchResult.NoMatch;
}
public static EMatchResult MatchNestedTypes(this TypeDefinition type, RemapSearchParams parms, ScoringModel score)
{
// Ignore types that dont have nested types when we are looking for them, and ignore types
// that have nested types while we're not looking for them
if ((type.HasNestedTypes is true && parms.NestedTypesToMatch.Count == 0) || (type.HasNestedTypes is false && parms.NestedTypesToMatch.Count > 0))
{
return EMatchResult.NoMatch;
}
// `*` is the wildcard to ignore all nested types that exist on types
if (parms.PropertyNamesToIgnore.Contains("*"))
{
return EMatchResult.NoMatch;
}
int matchCount = 0;
foreach (var nestedType in type.NestedTypes)
{
if (parms.NestedTypesToIgnore.Contains(nestedType.Name))
{
// Type contains blacklisted nested type
return EMatchResult.NoMatch;
}
if (parms.NestedTypesToMatch.Contains(nestedType.Name))
{
matchCount++;
score.Score += 2;
}
}
return matchCount > 0 ? EMatchResult.Match : EMatchResult.NoMatch;
}
}

View File

@ -0,0 +1,65 @@
using AssemblyRemapper.Models;
using Mono.Cecil;
using Newtonsoft.Json;
namespace AssemblyRemapper.Utils;
internal static class DataProvider
{
static DataProvider()
{
LoadAppSettings();
LoadAssemblyDefinition();
}
public static AppSettings AppSettings { get; private set; }
public static AssemblyDefinition AssemblyDefinition { get; private set; }
public static ModuleDefinition ModuleDefinition { get; private set; }
private static void LoadAppSettings()
{
var settingsPath = Path.Combine(AppContext.BaseDirectory, "Data", "Settings.jsonc");
if (!File.Exists(settingsPath))
{
throw new InvalidOperationException($"path `{settingsPath}` does not exist...");
}
var jsonText = File.ReadAllText(settingsPath);
JsonSerializerSettings settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
AppSettings = JsonConvert.DeserializeObject<AppSettings>(jsonText, settings);
}
private static void LoadAssemblyDefinition()
{
DefaultAssemblyResolver resolver = new();
resolver.AddSearchDirectory(Path.GetDirectoryName(AppSettings.AssemblyPath)); // Replace with the correct path
ReaderParameters parameters = new() { AssemblyResolver = resolver };
AssemblyDefinition = AssemblyDefinition.ReadAssembly(AppSettings.AssemblyPath, parameters);
if (AssemblyDefinition is null)
{
throw new InvalidOperationException("AssemblyDefinition was null...");
}
var fileName = Path.GetFileName(AppSettings.AssemblyPath);
foreach (var module in AssemblyDefinition.Modules.ToArray())
{
if (module.Name == fileName)
{
ModuleDefinition = module;
}
}
Logger.Log($"Module `{fileName}` not found in assembly {fileName}");
}
}

View File

@ -0,0 +1,35 @@
namespace AssemblyRemapper.Utils;
internal static class Logger
{
static Logger()
{
if (File.Exists(_logPath))
{
File.Delete(_logPath);
File.Create(_logPath).Close();
}
}
private static string _logPath = Path.Combine(AppContext.BaseDirectory, "Data", "Log.log");
public static void Log(string message, ConsoleColor color = ConsoleColor.Gray)
{
Console.ForegroundColor = color;
Console.WriteLine(message);
Console.ResetColor();
try
{
using (StreamWriter sw = File.AppendText(_logPath))
{
sw.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
}
}
catch (IOException ex)
{
// Handle potential file writing errors gracefully
Console.WriteLine($"Error logging: {ex.Message}");
}
}
}