using System; using System.Collections.Generic; using System.Linq; namespace BinaryObjectScanner.Matching { /// /// A set of path matches that work together /// public class PathMatchSet : MatchSet { /// /// Function to get a path version for this Matcher /// /// /// A path version method takes the matched path and an enumerable of files /// and returns a single string. That string is either a version string, /// in which case it will be appended to the protection name, or `null`, /// in which case it will cause the protection to be omitted. /// #if NET48 public Func, string> GetVersion { get; private set; } #else public Func, string>? GetVersion { get; init; } #endif #region Constructors public PathMatchSet(string needle, string protectionName) : this(new List { needle }, null, protectionName) { } public PathMatchSet(List needles, string protectionName) : this(needles, null, protectionName) { } #if NET48 public PathMatchSet(string needle, Func, string> getVersion, string protectionName) : this(new List { needle }, getVersion, protectionName) { } public PathMatchSet(List needles, Func, string> getVersion, string protectionName) : this(needles.Select(n => new PathMatch(n)).ToList(), getVersion, protectionName) { } #else public PathMatchSet(string needle, Func, string>? getVersion, string protectionName) : this(new List { needle }, getVersion, protectionName) { } public PathMatchSet(List needles, Func, string>? getVersion, string protectionName) : this(needles.Select(n => new PathMatch(n)).ToList(), getVersion, protectionName) { } #endif public PathMatchSet(PathMatch needle, string protectionName) : this(new List() { needle }, null, protectionName) { } public PathMatchSet(List needles, string protectionName) : this(needles, null, protectionName) { } #if NET48 public PathMatchSet(PathMatch needle, Func, string> getVersion, string protectionName) : this(new List() { needle }, getVersion, protectionName) { } public PathMatchSet(List needles, Func, string> getVersion, string protectionName) { Matchers = needles; GetVersion = getVersion; ProtectionName = protectionName; } #else public PathMatchSet(PathMatch needle, Func, string>? getVersion, string protectionName) : this(new List() { needle }, getVersion, protectionName) { } public PathMatchSet(List needles, Func, string>? getVersion, string protectionName) { Matchers = needles; GetVersion = getVersion; ProtectionName = protectionName; } #endif #endregion #region Matching /// /// Determine whether all path matches pass /// /// List of strings to try to match /// Tuple of passing status and matching values public (bool, List) MatchesAll(IEnumerable stack) { // If no path matches are defined, we fail out if (Matchers == null || !Matchers.Any()) return (false, new List()); // Initialize the value list List values = new List(); // Loop through all path matches and make sure all pass foreach (var pathMatch in Matchers) { #if NET48 (bool match, string value) = pathMatch.Match(stack); #else (bool match, string? value) = pathMatch.Match(stack); #endif if (!match || value == null) return (false, new List()); else values.Add(value); } return (true, values); } /// /// Determine whether any path matches pass /// /// List of strings to try to match /// Tuple of passing status and first matching value #if NET48 public (bool, string) MatchesAny(IEnumerable stack) #else public (bool, string?) MatchesAny(IEnumerable stack) #endif { // If no path matches are defined, we fail out if (Matchers == null || !Matchers.Any()) return (false, null); // Loop through all path matches and make sure all pass foreach (var pathMatch in Matchers) { #if NET48 (bool match, string value) = pathMatch.Match(stack); #else (bool match, string? value) = pathMatch.Match(stack); #endif if (match) return (true, value); } return (false, null); } #endregion } }