Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/AsmResolver.DotNet/AssemblyResolverBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace AsmResolver.DotNet
/// </summary>
public abstract class AssemblyResolverBase : IAssemblyResolver
{
private static readonly string[] BinaryFileExtensions = [".dll", ".exe"];
internal static readonly string[] BinaryFileExtensions = [".dll", ".exe"];

/// <summary>
/// Initializes the base of an assembly resolver.
Expand Down
19 changes: 19 additions & 0 deletions src/AsmResolver.DotNet/NullAssemblyResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace AsmResolver.DotNet;

/// <summary>
/// Provides an implementation of an assembly resolver that always resolves to <see cref="ResolutionStatus.AssemblyNotFound"/>.
/// </summary>
public sealed class NullAssemblyResolver : IAssemblyResolver
{
/// <summary>
/// Gets the singleton instance of the <see cref="NullAssemblyResolver"/> class.
/// </summary>
public static NullAssemblyResolver Instance { get; } = new();

/// <inheritdoc />
public ResolutionStatus Resolve(AssemblyDescriptor assembly, ModuleDefinition? originModule, out AssemblyDefinition? result)
{
result = null;
return ResolutionStatus.AssemblyNotFound;
}
}
92 changes: 92 additions & 0 deletions src/AsmResolver.DotNet/PathAssemblyResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AsmResolver.DotNet.Serialized;

namespace AsmResolver.DotNet;

/// <summary>
/// Provides an implementation of an assembly resolver that resolves assemblies from a provided set of file paths.
/// </summary>
public sealed class PathAssemblyResolver : IAssemblyResolver
{
private readonly Dictionary<string, string> _simpleNameMap = new(StringComparer.OrdinalIgnoreCase);

/// <summary>
/// Creates a new path assembly resolver.
/// </summary>
/// <param name="referencePath">The set of file paths used when resolving assemblies.</param>
/// <param name="readerParameters">The reader parameters used for reading new resolved assemblies.</param>
public PathAssemblyResolver(IEnumerable<string> referencePath, ModuleReaderParameters? readerParameters = null)
{
var paths = referencePath as ICollection<string> ?? referencePath.ToArray();

foreach (string extension in AssemblyResolverBase.BinaryFileExtensions)
{
foreach (string path in paths)
{
if (!path.EndsWith(extension, StringComparison.OrdinalIgnoreCase) || !File.Exists(path))
continue;

string simpleName = Path.GetFileNameWithoutExtension(path);
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
_simpleNameMap.TryAdd(simpleName, path);
#else
if (!_simpleNameMap.ContainsKey(simpleName))
{
_simpleNameMap.Add(simpleName, path);
}
#endif
}
}

ReaderParameters = readerParameters;
}

/// <summary>
/// Creates a new path assembly resolver from provided <paramref name="searchDirectories"/>.
/// </summary>
/// <param name="searchDirectories">The search directories used to construct the reference path.</param>
/// <param name="readerParameters">The reader parameters used for reading new resolved assemblies.</param>
/// <remarks>The directories are traversed at the time of this call, so any later filesystem changes won't be reflected.</remarks>
public static PathAssemblyResolver FromSearchDirectories(IEnumerable<string> searchDirectories, ModuleReaderParameters? readerParameters = null)
{
var referencePath = new List<string>();
foreach (string directory in searchDirectories)
{
if (!Directory.Exists(directory))
continue;

referencePath.AddRange(Directory.GetFiles(directory));
}

return new PathAssemblyResolver(referencePath, readerParameters);
}

/// <summary>
/// Gets the reader parameters used for reading new resolved assemblies.
/// </summary>
public ModuleReaderParameters? ReaderParameters { get; }

/// <inheritdoc />
public ResolutionStatus Resolve(AssemblyDescriptor assembly, ModuleDefinition? originModule, out AssemblyDefinition? result)
{
if (assembly.Name is null || !_simpleNameMap.TryGetValue(assembly.Name, out string path))

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Build

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (windows-2025, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (windows-2025, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (windows-2025, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (windows-2025, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (windows-2025, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (ubuntu-24.04, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (ubuntu-24.04, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (ubuntu-24.04, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (ubuntu-24.04, x64)

Converting null literal or possible null value to non-nullable type.

Check warning on line 75 in src/AsmResolver.DotNet/PathAssemblyResolver.cs

View workflow job for this annotation

GitHub Actions / Test (ubuntu-24.04, x64)

Converting null literal or possible null value to non-nullable type.
{
result = null;
return ResolutionStatus.AssemblyNotFound;
}

try
{
result = AssemblyDefinition.FromFile(path, readerParameters: ReaderParameters, createRuntimeContext: false);
return ResolutionStatus.Success;
}
catch (BadImageFormatException)
{
result = null;
return ResolutionStatus.AssemblyBadImage;
}
}
}
42 changes: 42 additions & 0 deletions test/AsmResolver.DotNet.Tests/AssemblyResolverTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -431,5 +431,47 @@ static void PrepareTestEnvironment(string basePath)
);
}
}

[Fact]
public void ResolveUsingNullResolver()
{
var assemblyRef = KnownCorLibs.SystemPrivateCoreLib_v10_0_0_0;

var defaultResolver = new DotNetCoreAssemblyResolver(new Version(10, 0));
var nullResolver = NullAssemblyResolver.Instance;

Assert.Equal(ResolutionStatus.Success, defaultResolver.Resolve(assemblyRef, null, out _));
Assert.Equal(ResolutionStatus.AssemblyNotFound, nullResolver.Resolve(assemblyRef, null, out _));
}

[Theory]
[InlineData(new[] { "Hello.exe", "Hello.dll" }, "Hello", "Hello.dll")]
[InlineData(new[] { "Hello.exe" }, "Hello", "Hello.exe")]
[InlineData(new[] { "case.DLL", "Case.dll" }, "Case", "case.DLL")]
public void ResolveUsingReferencePathResolver(string[] fileNames, string reference, string resolvedFileName)
{
string basePath = _fixture.GetRunner<CorePERunner>().GetTestDirectory();

var referencePaths = new string[fileNames.Length];
for (var i = 0; i < fileNames.Length; i++)
{
var path = referencePaths[i] = Path.Combine(basePath, fileNames[i]);
WriteAssembly(path);
}

var resolver = new PathAssemblyResolver(referencePaths);
var status = resolver.Resolve(new AssemblyReference(reference, new Version()), null, out var assemblyDef);

Assert.Equal(ResolutionStatus.Success, status);
Assert.Equal(resolvedFileName, Path.GetFileName(assemblyDef!.ManifestModule!.FilePath));

static void WriteAssembly(string path)
{
var assembly = new AssemblyDefinition(Path.GetFileNameWithoutExtension(path), new Version(1, 0, 0, 0));
var module = new ModuleDefinition(Path.GetFileName(path), KnownCorLibs.SystemRuntime_v10_0_0_0);
assembly.Modules.Add(module);
assembly.Write(path);
}
}
}
}
Loading