using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace BinaryObjectScanner.Matching { /// /// A set of content matches that work together /// public class ContentMatchSet : MatchSet { /// /// Function to get a content version /// /// /// A content version method takes the file path, the file contents, /// and a list of found positions 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. /// public Func, string> GetArrayVersion { get; set; } /// /// Function to get a content version /// /// /// A content version method takes the file path, the file contents, /// and a list of found positions 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. /// public Func, string> GetStreamVersion { get; set; } #region Generic Constructors public ContentMatchSet(byte?[] needle, string protectionName) : this(new List { needle }, getArrayVersion: null, protectionName) { } public ContentMatchSet(List needles, string protectionName) : this(needles, getArrayVersion: null, protectionName) { } public ContentMatchSet(ContentMatch needle, string protectionName) : this(new List() { needle }, getArrayVersion: null, protectionName) { } public ContentMatchSet(List needles, string protectionName) : this(needles, getArrayVersion: null, protectionName) { } #endregion #region Array Constructors public ContentMatchSet(byte?[] needle, Func, string> getArrayVersion, string protectionName) : this(new List { needle }, getArrayVersion, protectionName) { } public ContentMatchSet(List needles, Func, string> getArrayVersion, string protectionName) : this(needles.Select(n => new ContentMatch(n)).ToList(), getArrayVersion, protectionName) { } public ContentMatchSet(ContentMatch needle, Func, string> getArrayVersion, string protectionName) : this(new List() { needle }, getArrayVersion, protectionName) { } public ContentMatchSet(List needles, Func, string> getArrayVersion, string protectionName) { Matchers = needles; GetArrayVersion = getArrayVersion; ProtectionName = protectionName; } #endregion #region Stream Constructors public ContentMatchSet(byte?[] needle, Func, string> getStreamVersion, string protectionName) : this(new List { needle }, getStreamVersion, protectionName) { } public ContentMatchSet(List needles, Func, string> getStreamVersion, string protectionName) : this(needles.Select(n => new ContentMatch(n)).ToList(), getStreamVersion, protectionName) { } public ContentMatchSet(ContentMatch needle, Func, string> getStreamVersion, string protectionName) : this(new List() { needle }, getStreamVersion, protectionName) { } public ContentMatchSet(List needles, Func, string> getStreamVersion, string protectionName) { Matchers = needles; GetStreamVersion = getStreamVersion; ProtectionName = protectionName; } #endregion #region Array Matching /// /// Determine whether all content matches pass /// /// Array to search /// Tuple of passing status and matching positions public (bool, List) MatchesAll(byte[] stack) { // If no content matches are defined, we fail out if (Matchers == null || !Matchers.Any()) return (false, new List()); // Initialize the position list List positions = new List(); // Loop through all content matches and make sure all pass foreach (var contentMatch in Matchers) { (bool match, int position) = contentMatch.Match(stack); if (!match) return (false, new List()); else positions.Add(position); } return (true, positions); } /// /// Determine whether any content matches pass /// /// Array to search /// Tuple of passing status and first matching position public (bool, int) MatchesAny(byte[] stack) { // If no content matches are defined, we fail out if (Matchers == null || !Matchers.Any()) return (false, -1); // Loop through all content matches and make sure all pass foreach (var contentMatch in Matchers) { (bool match, int position) = contentMatch.Match(stack); if (match) return (true, position); } return (false, -1); } #endregion #region Stream Matching /// /// Determine whether all content matches pass /// /// Stream to search /// Tuple of passing status and matching positions public (bool, List) MatchesAll(Stream stack) { // If no content matches are defined, we fail out if (Matchers == null || !Matchers.Any()) return (false, new List()); // Initialize the position list List positions = new List(); // Loop through all content matches and make sure all pass foreach (var contentMatch in Matchers) { (bool match, int position) = contentMatch.Match(stack); if (!match) return (false, new List()); else positions.Add(position); } return (true, positions); } /// /// Determine whether any content matches pass /// /// Stream to search /// Tuple of passing status and first matching position public (bool, int) MatchesAny(Stream stack) { // If no content matches are defined, we fail out if (Matchers == null || !Matchers.Any()) return (false, -1); // Loop through all content matches and make sure all pass foreach (var contentMatch in Matchers) { (bool match, int position) = contentMatch.Match(stack); if (match) return (true, position); } return (false, -1); } #endregion } }