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
}
}