mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-09-21 22:34:58 +00:00
Add nullability to matching library, fix warnings
This commit is contained in:
@@ -19,4 +19,8 @@
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)'!='net48'">
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -10,17 +10,25 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <summary>
|
||||
/// Content to match
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public byte?[] Needle { get; set; }
|
||||
#else
|
||||
public byte?[]? Needle { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Starting index for matching
|
||||
/// </summary>
|
||||
public int Start { get; set; }
|
||||
public int Start { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ending index for matching
|
||||
/// </summary>
|
||||
public int End { get; set; }
|
||||
#if NET48
|
||||
public int End { get; private set; }
|
||||
#else
|
||||
public int End { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
@@ -28,11 +36,15 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="needle">Byte array representing the search</param>
|
||||
/// <param name="start">Optional starting index</param>
|
||||
/// <param name="end">Optional ending index</param>
|
||||
#if NET48
|
||||
public ContentMatch(byte?[] needle, int start = -1, int end = -1)
|
||||
#else
|
||||
public ContentMatch(byte?[]? needle, int start = -1, int end = -1)
|
||||
#endif
|
||||
{
|
||||
Needle = needle;
|
||||
Start = start;
|
||||
End = end;
|
||||
this.Needle = needle;
|
||||
this.Start = start;
|
||||
this.End = end;
|
||||
}
|
||||
|
||||
#region Array Matching
|
||||
@@ -46,22 +58,22 @@ namespace BinaryObjectScanner.Matching
|
||||
public (bool success, int position) Match(byte[] stack, bool reverse = false)
|
||||
{
|
||||
// If either array is null or empty, we can't do anything
|
||||
if (stack == null || stack.Length == 0 || Needle == null || Needle.Length == 0)
|
||||
if (stack == null || stack.Length == 0 || this.Needle == null || this.Needle.Length == 0)
|
||||
return (false, -1);
|
||||
|
||||
// If the needle array is larger than the stack array, it can't be contained within
|
||||
if (Needle.Length > stack.Length)
|
||||
if (this.Needle.Length > stack.Length)
|
||||
return (false, -1);
|
||||
|
||||
// Set the default start and end values
|
||||
int start = Start;
|
||||
int end = End;
|
||||
int start = this.Start;
|
||||
int end = this.End;
|
||||
|
||||
// If start or end are not set properly, set them to defaults
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (end < 0)
|
||||
end = stack.Length - Needle.Length;
|
||||
end = stack.Length - this.Needle.Length;
|
||||
|
||||
for (int i = reverse ? end : start; reverse ? i > start : i < end; i += reverse ? -1 : 1)
|
||||
{
|
||||
@@ -85,21 +97,25 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <returns>True if the needle matches the stack at a given index</returns>
|
||||
private bool EqualAt(byte[] stack, int index)
|
||||
{
|
||||
// If the needle is invalid, we can't do anything
|
||||
if (this.Needle == null)
|
||||
return false;
|
||||
|
||||
// If the index is invalid, we can't do anything
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
// If we're too close to the end of the stack, return false
|
||||
if (Needle.Length > stack.Length - index)
|
||||
if (this.Needle.Length > stack.Length - index)
|
||||
return false;
|
||||
|
||||
// Loop through and check the value
|
||||
for (int i = 0; i < Needle.Length; i++)
|
||||
for (int i = 0; i < this.Needle.Length; i++)
|
||||
{
|
||||
// A null value is a wildcard
|
||||
if (Needle[i] == null)
|
||||
if (this.Needle[i] == null)
|
||||
continue;
|
||||
else if (stack[i + index] != Needle[i])
|
||||
else if (stack[i + index] != this.Needle[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -119,22 +135,22 @@ namespace BinaryObjectScanner.Matching
|
||||
public (bool success, int position) Match(Stream stack, bool reverse = false)
|
||||
{
|
||||
// If either array is null or empty, we can't do anything
|
||||
if (stack == null || stack.Length == 0 || Needle == null || Needle.Length == 0)
|
||||
if (stack == null || stack.Length == 0 || this.Needle == null || this.Needle.Length == 0)
|
||||
return (false, -1);
|
||||
|
||||
// If the needle array is larger than the stack array, it can't be contained within
|
||||
if (Needle.Length > stack.Length)
|
||||
if (this.Needle.Length > stack.Length)
|
||||
return (false, -1);
|
||||
|
||||
// Set the default start and end values
|
||||
int start = Start;
|
||||
int end = End;
|
||||
int start = this.Start;
|
||||
int end = this.End;
|
||||
|
||||
// If start or end are not set properly, set them to defaults
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (end < 0)
|
||||
end = (int)(stack.Length - Needle.Length);
|
||||
end = (int)(stack.Length - this.Needle.Length);
|
||||
|
||||
for (int i = reverse ? end : start; reverse ? i > start : i < end; i += reverse ? -1 : 1)
|
||||
{
|
||||
@@ -158,12 +174,16 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <returns>True if the needle matches the stack at a given index</returns>
|
||||
private bool EqualAt(Stream stack, int index)
|
||||
{
|
||||
// If the needle is invalid, we can't do anything
|
||||
if (this.Needle == null)
|
||||
return false;
|
||||
|
||||
// If the index is invalid, we can't do anything
|
||||
if (index < 0)
|
||||
return false;
|
||||
|
||||
// If we're too close to the end of the stack, return false
|
||||
if (Needle.Length > stack.Length - index)
|
||||
if (this.Needle.Length > stack.Length - index)
|
||||
return false;
|
||||
|
||||
// Save the current position and move to the index
|
||||
@@ -174,16 +194,16 @@ namespace BinaryObjectScanner.Matching
|
||||
bool matched = true;
|
||||
|
||||
// Loop through and check the value
|
||||
for (int i = 0; i < Needle.Length; i++)
|
||||
for (int i = 0; i < this.Needle.Length; i++)
|
||||
{
|
||||
byte stackValue = (byte)stack.ReadByte();
|
||||
|
||||
// A null value is a wildcard
|
||||
if (Needle[i] == null)
|
||||
if (this.Needle[i] == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (stackValue != Needle[i])
|
||||
else if (stackValue != this.Needle[i])
|
||||
{
|
||||
matched = false;
|
||||
break;
|
||||
|
||||
@@ -20,7 +20,11 @@ namespace BinaryObjectScanner.Matching
|
||||
/// to the protection name, or `null`, in which case it will cause
|
||||
/// the protection to be omitted.
|
||||
/// </remarks>
|
||||
public Func<string, byte[], List<int>, string> GetArrayVersion { get; set; }
|
||||
#if NET48
|
||||
public Func<string, byte[], List<int>, string> GetArrayVersion { get; private set; }
|
||||
#else
|
||||
public Func<string, byte[], List<int>, string>? GetArrayVersion { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Function to get a content version
|
||||
@@ -32,7 +36,11 @@ namespace BinaryObjectScanner.Matching
|
||||
/// to the protection name, or `null`, in which case it will cause
|
||||
/// the protection to be omitted.
|
||||
/// </remarks>
|
||||
public Func<string, Stream, List<int>, string> GetStreamVersion { get; set; }
|
||||
#if NET48
|
||||
public Func<string, Stream, List<int>, string> GetStreamVersion { get; private set; }
|
||||
#else
|
||||
public Func<string, Stream, List<int>, string>? GetStreamVersion { get; init; }
|
||||
#endif
|
||||
|
||||
#region Generic Constructors
|
||||
|
||||
@@ -52,6 +60,7 @@ namespace BinaryObjectScanner.Matching
|
||||
|
||||
#region Array Constructors
|
||||
|
||||
#if NET48
|
||||
public ContentMatchSet(byte?[] needle, Func<string, byte[], List<int>, string> getArrayVersion, string protectionName)
|
||||
: this(new List<byte?[]> { needle }, getArrayVersion, protectionName) { }
|
||||
|
||||
@@ -67,11 +76,29 @@ namespace BinaryObjectScanner.Matching
|
||||
GetArrayVersion = getArrayVersion;
|
||||
ProtectionName = protectionName;
|
||||
}
|
||||
#else
|
||||
public ContentMatchSet(byte?[] needle, Func<string, byte[], List<int>, string>? getArrayVersion, string protectionName)
|
||||
: this(new List<byte?[]> { needle }, getArrayVersion, protectionName) { }
|
||||
|
||||
public ContentMatchSet(List<byte?[]> needles, Func<string, byte[], List<int>, string>? getArrayVersion, string protectionName)
|
||||
: this(needles.Select(n => new ContentMatch(n)).ToList(), getArrayVersion, protectionName) { }
|
||||
|
||||
public ContentMatchSet(ContentMatch needle, Func<string, byte[], List<int>, string>? getArrayVersion, string protectionName)
|
||||
: this(new List<ContentMatch>() { needle }, getArrayVersion, protectionName) { }
|
||||
|
||||
public ContentMatchSet(List<ContentMatch> needles, Func<string, byte[], List<int>, string>? getArrayVersion, string protectionName)
|
||||
{
|
||||
Matchers = needles;
|
||||
GetArrayVersion = getArrayVersion;
|
||||
ProtectionName = protectionName;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region Stream Constructors
|
||||
|
||||
#if NET48
|
||||
public ContentMatchSet(byte?[] needle, Func<string, Stream, List<int>, string> getStreamVersion, string protectionName)
|
||||
: this(new List<byte?[]> { needle }, getStreamVersion, protectionName) { }
|
||||
|
||||
@@ -87,6 +114,23 @@ namespace BinaryObjectScanner.Matching
|
||||
GetStreamVersion = getStreamVersion;
|
||||
ProtectionName = protectionName;
|
||||
}
|
||||
#else
|
||||
public ContentMatchSet(byte?[] needle, Func<string, Stream, List<int>, string>? getStreamVersion, string protectionName)
|
||||
: this(new List<byte?[]> { needle }, getStreamVersion, protectionName) { }
|
||||
|
||||
public ContentMatchSet(List<byte?[]> needles, Func<string, Stream, List<int>, string>? getStreamVersion, string protectionName)
|
||||
: this(needles.Select(n => new ContentMatch(n)).ToList(), getStreamVersion, protectionName) { }
|
||||
|
||||
public ContentMatchSet(ContentMatch needle, Func<string, Stream, List<int>, string>? getStreamVersion, string protectionName)
|
||||
: this(new List<ContentMatch>() { needle }, getStreamVersion, protectionName) { }
|
||||
|
||||
public ContentMatchSet(List<ContentMatch> needles, Func<string, Stream, List<int>, string>? getStreamVersion, string protectionName)
|
||||
{
|
||||
Matchers = needles;
|
||||
GetStreamVersion = getStreamVersion;
|
||||
ProtectionName = protectionName;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -96,7 +140,7 @@ namespace BinaryObjectScanner.Matching
|
||||
/// Determine whether all content matches pass
|
||||
/// </summary>
|
||||
/// <param name="stack">Array to search</param>
|
||||
/// <returns>Tuple of passing status and matching positions</returns>
|
||||
/// <returns>Tuple of passing status and matching positions</returns>
|
||||
public (bool, List<int>) MatchesAll(byte[] stack)
|
||||
{
|
||||
// If no content matches are defined, we fail out
|
||||
@@ -104,7 +148,7 @@ namespace BinaryObjectScanner.Matching
|
||||
return (false, new List<int>());
|
||||
|
||||
// Initialize the position list
|
||||
List<int> positions = new List<int>();
|
||||
var positions = new List<int>();
|
||||
|
||||
// Loop through all content matches and make sure all pass
|
||||
foreach (var contentMatch in Matchers)
|
||||
@@ -123,7 +167,7 @@ namespace BinaryObjectScanner.Matching
|
||||
/// Determine whether any content matches pass
|
||||
/// </summary>
|
||||
/// <param name="stack">Array to search</param>
|
||||
/// <returns>Tuple of passing status and first matching position</returns>
|
||||
/// <returns>Tuple of passing status and first matching position</returns>
|
||||
public (bool, int) MatchesAny(byte[] stack)
|
||||
{
|
||||
// If no content matches are defined, we fail out
|
||||
@@ -149,7 +193,7 @@ namespace BinaryObjectScanner.Matching
|
||||
/// Determine whether all content matches pass
|
||||
/// </summary>
|
||||
/// <param name="stack">Stream to search</param>
|
||||
/// <returns>Tuple of passing status and matching positions</returns>
|
||||
/// <returns>Tuple of passing status and matching positions</returns>
|
||||
public (bool, List<int>) MatchesAll(Stream stack)
|
||||
{
|
||||
// If no content matches are defined, we fail out
|
||||
@@ -176,7 +220,7 @@ namespace BinaryObjectScanner.Matching
|
||||
/// Determine whether any content matches pass
|
||||
/// </summary>
|
||||
/// <param name="stack">Stream to search</param>
|
||||
/// <returns>Tuple of passing status and first matching position</returns>
|
||||
/// <returns>Tuple of passing status and first matching position</returns>
|
||||
public (bool, int) MatchesAny(Stream stack)
|
||||
{
|
||||
// If no content matches are defined, we fail out
|
||||
|
||||
@@ -33,16 +33,28 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <summary>
|
||||
/// Find the first position of one array in another, if possible
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static bool FirstPosition(this byte[] stack, byte[] needle, out int position, int start = 0, int end = -1)
|
||||
{
|
||||
byte?[] nullableNeedle = needle != null ? needle.Select(b => (byte?)b).ToArray() : null;
|
||||
return stack.FirstPosition(nullableNeedle, out position, start, end);
|
||||
}
|
||||
#else
|
||||
public static bool FirstPosition(this byte[] stack, byte[]? needle, out int position, int start = 0, int end = -1)
|
||||
{
|
||||
byte?[]? nullableNeedle = needle != null ? needle.Select(b => (byte?)b).ToArray() : null;
|
||||
return stack.FirstPosition(nullableNeedle, out position, start, end);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Find the first position of one array in another, if possible
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static bool FirstPosition(this byte[] stack, byte?[] needle, out int position, int start = 0, int end = -1)
|
||||
#else
|
||||
public static bool FirstPosition(this byte[] stack, byte?[]? needle, out int position, int start = 0, int end = -1)
|
||||
#endif
|
||||
{
|
||||
var matcher = new ContentMatch(needle, start, end);
|
||||
(bool found, int foundPosition) = matcher.Match(stack, false);
|
||||
@@ -53,7 +65,11 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <summary>
|
||||
/// Find the last position of one array in another, if possible
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public static bool LastPosition(this byte[] stack, byte?[] needle, out int position, int start = 0, int end = -1)
|
||||
#else
|
||||
public static bool LastPosition(this byte[] stack, byte?[]? needle, out int position, int start = 0, int end = -1)
|
||||
#endif
|
||||
{
|
||||
var matcher = new ContentMatch(needle, start, end);
|
||||
(bool found, int foundPosition) = matcher.Match(stack, true);
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
{
|
||||
public interface IMatch<T>
|
||||
{
|
||||
#if NET48
|
||||
T Needle { get; set; }
|
||||
#else
|
||||
T? Needle { get; init; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,19 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <summary>
|
||||
/// Set of all matchers
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public IEnumerable<T> Matchers { get; set; }
|
||||
#else
|
||||
public IEnumerable<T>? Matchers { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Name of the protection to show
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string ProtectionName { get; set; }
|
||||
#else
|
||||
public string? ProtectionName { get; set; }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,11 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
public static ConcurrentQueue<string> GetAllMatches(
|
||||
string file,
|
||||
byte[] stack,
|
||||
IEnumerable<ContentMatchSet> matchers,
|
||||
bool includeDebug = false)
|
||||
#if NET48
|
||||
public static ConcurrentQueue<string> GetAllMatches(string file, byte[] stack, IEnumerable<ContentMatchSet> matchers, bool includeDebug = false)
|
||||
#else
|
||||
public static ConcurrentQueue<string>? GetAllMatches(string file, byte[] stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug = false)
|
||||
#endif
|
||||
{
|
||||
return FindAllMatches(file, stack, matchers, includeDebug, false);
|
||||
}
|
||||
@@ -37,16 +37,16 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <returns>String representing the matched protection, null otherwise</returns>
|
||||
public static string GetFirstMatch(
|
||||
string file,
|
||||
byte[] stack,
|
||||
IEnumerable<ContentMatchSet> matchers,
|
||||
bool includeDebug = false)
|
||||
#if NET48
|
||||
public static string GetFirstMatch(string file, byte[] stack, IEnumerable<ContentMatchSet> matchers, bool includeDebug = false)
|
||||
#else
|
||||
public static string? GetFirstMatch(string file, byte[] stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug = false)
|
||||
#endif
|
||||
{
|
||||
var contentMatches = FindAllMatches(file, stack, matchers, includeDebug, true);
|
||||
if (contentMatches == null || !contentMatches.Any())
|
||||
return null;
|
||||
|
||||
|
||||
return contentMatches.First();
|
||||
}
|
||||
|
||||
@@ -58,13 +58,12 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
private static ConcurrentQueue<string> FindAllMatches(
|
||||
string file,
|
||||
byte[] stack,
|
||||
IEnumerable<ContentMatchSet> matchers,
|
||||
bool includeDebug,
|
||||
bool stopAfterFirst)
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET48
|
||||
private static ConcurrentQueue<string> FindAllMatches(string file, byte[] stack, IEnumerable<ContentMatchSet> matchers, bool includeDebug, bool stopAfterFirst)
|
||||
#else
|
||||
private static ConcurrentQueue<string>? FindAllMatches(string file, byte[] stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug, bool stopAfterFirst)
|
||||
#endif
|
||||
{
|
||||
// If there's no mappings, we can't match
|
||||
if (matchers == null || !matchers.Any())
|
||||
@@ -121,11 +120,11 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
public static ConcurrentQueue<string> GetAllMatches(
|
||||
string file,
|
||||
Stream stack,
|
||||
IEnumerable<ContentMatchSet> matchers,
|
||||
bool includeDebug = false)
|
||||
#if NET48
|
||||
public static ConcurrentQueue<string> GetAllMatches(string file, Stream stack, IEnumerable<ContentMatchSet> matchers, bool includeDebug = false)
|
||||
#else
|
||||
public static ConcurrentQueue<string>? GetAllMatches(string file, Stream stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug = false)
|
||||
#endif
|
||||
{
|
||||
return FindAllMatches(file, stack, matchers, includeDebug, false);
|
||||
}
|
||||
@@ -138,11 +137,11 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <returns>String representing the matched protection, null otherwise</returns>
|
||||
public static string GetFirstMatch(
|
||||
string file,
|
||||
Stream stack,
|
||||
IEnumerable<ContentMatchSet> matchers,
|
||||
bool includeDebug = false)
|
||||
#if NET48
|
||||
public static string GetFirstMatch(string file, Stream stack, IEnumerable<ContentMatchSet> matchers, bool includeDebug = false)
|
||||
#else
|
||||
public static string? GetFirstMatch(string file, Stream stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug = false)
|
||||
#endif
|
||||
{
|
||||
var contentMatches = FindAllMatches(file, stack, matchers, includeDebug, true);
|
||||
if (contentMatches == null || !contentMatches.Any())
|
||||
@@ -159,13 +158,12 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of ContentMatchSets to be run on the file</param>
|
||||
/// <param name="includeDebug">True to include positional data, false otherwise</param>
|
||||
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
private static ConcurrentQueue<string> FindAllMatches(
|
||||
string file,
|
||||
Stream stack,
|
||||
IEnumerable<ContentMatchSet> matchers,
|
||||
bool includeDebug,
|
||||
bool stopAfterFirst)
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
#if NET48
|
||||
private static ConcurrentQueue<string> FindAllMatches(string file, Stream stack, IEnumerable<ContentMatchSet> matchers, bool includeDebug, bool stopAfterFirst)
|
||||
#else
|
||||
private static ConcurrentQueue<string>? FindAllMatches(string file, Stream stack, IEnumerable<ContentMatchSet>? matchers, bool includeDebug, bool stopAfterFirst)
|
||||
#endif
|
||||
{
|
||||
// If there's no mappings, we can't match
|
||||
if (matchers == null || !matchers.Any())
|
||||
@@ -245,12 +243,16 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
|
||||
/// <param name="any">True if any path match is a success, false if all have to match</param>
|
||||
/// <returns>String representing the matched protection, null otherwise</returns>
|
||||
#if NET48
|
||||
public static string GetFirstMatch(string file, IEnumerable<PathMatchSet> matchers, bool any = false)
|
||||
#else
|
||||
public static string? GetFirstMatch(string file, IEnumerable<PathMatchSet> matchers, bool any = false)
|
||||
#endif
|
||||
{
|
||||
var contentMatches = FindAllMatches(new List<string> { file }, matchers, any, true);
|
||||
if (contentMatches == null || !contentMatches.Any())
|
||||
return null;
|
||||
|
||||
|
||||
return contentMatches.First();
|
||||
}
|
||||
|
||||
@@ -261,12 +263,16 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
|
||||
/// <param name="any">True if any path match is a success, false if all have to match</param>
|
||||
/// <returns>String representing the matched protection, null otherwise</returns>
|
||||
#if NET48
|
||||
public static string GetFirstMatch(IEnumerable<string> files, IEnumerable<PathMatchSet> matchers, bool any = false)
|
||||
#else
|
||||
public static string? GetFirstMatch(IEnumerable<string> files, IEnumerable<PathMatchSet> matchers, bool any = false)
|
||||
#endif
|
||||
{
|
||||
var contentMatches = FindAllMatches(files, matchers, any, true);
|
||||
if (contentMatches == null || !contentMatches.Any())
|
||||
return null;
|
||||
|
||||
|
||||
return contentMatches.First();
|
||||
}
|
||||
|
||||
@@ -277,7 +283,7 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="matchers">Enumerable of PathMatchSets to be run on the file</param>
|
||||
/// <param name="any">True if any path match is a success, false if all have to match</param>
|
||||
/// <param name="stopAfterFirst">True to stop after the first match, false otherwise</param>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
/// <returns>List of strings representing the matched protections, null or empty otherwise</returns>
|
||||
private static ConcurrentQueue<string> FindAllMatches(IEnumerable<string> files, IEnumerable<PathMatchSet> matchers, bool any, bool stopAfterFirst)
|
||||
{
|
||||
// If there's no mappings, we can't match
|
||||
@@ -292,10 +298,18 @@ namespace BinaryObjectScanner.Matching
|
||||
{
|
||||
// Determine if the matcher passes
|
||||
bool passes;
|
||||
#if NET48
|
||||
string firstMatchedString;
|
||||
#else
|
||||
string? firstMatchedString;
|
||||
#endif
|
||||
if (any)
|
||||
{
|
||||
#if NET48
|
||||
(bool anyPasses, string matchedString) = matcher.MatchesAny(files);
|
||||
#else
|
||||
(bool anyPasses, string? matchedString) = matcher.MatchesAny(files);
|
||||
#endif
|
||||
passes = anyPasses;
|
||||
firstMatchedString = matchedString;
|
||||
}
|
||||
@@ -305,9 +319,9 @@ namespace BinaryObjectScanner.Matching
|
||||
passes = allPasses;
|
||||
firstMatchedString = matchedStrings.FirstOrDefault();
|
||||
}
|
||||
|
||||
|
||||
// If we don't have a pass, just continue
|
||||
if (!passes)
|
||||
if (!passes || firstMatchedString == null)
|
||||
continue;
|
||||
|
||||
// If we there is no version method, just return the protection name
|
||||
@@ -334,7 +348,7 @@ namespace BinaryObjectScanner.Matching
|
||||
|
||||
return matchedProtections;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -11,17 +11,29 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <summary>
|
||||
/// String to match
|
||||
/// </summary>
|
||||
#if NET48
|
||||
public string Needle { get; set; }
|
||||
#else
|
||||
public string? Needle { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Match exact casing instead of invariant
|
||||
/// </summary>
|
||||
public bool MatchExact { get; set; }
|
||||
#if NET48
|
||||
public bool MatchExact { get; private set; }
|
||||
#else
|
||||
public bool MatchExact { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Match that values end with the needle and not just contains
|
||||
/// </summary>
|
||||
public bool UseEndsWith { get; set; }
|
||||
#if NET48
|
||||
public bool UseEndsWith { get; private set; }
|
||||
#else
|
||||
public bool UseEndsWith { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
@@ -29,11 +41,15 @@ namespace BinaryObjectScanner.Matching
|
||||
/// <param name="needle">String representing the search</param>
|
||||
/// <param name="matchExact">True to match exact casing, false otherwise</param>
|
||||
/// <param name="useEndsWith">True to match the end only, false for all contents</param>
|
||||
#if NET48
|
||||
public PathMatch(string needle, bool matchExact = false, bool useEndsWith = false)
|
||||
#else
|
||||
public PathMatch(string? needle, bool matchExact = false, bool useEndsWith = false)
|
||||
#endif
|
||||
{
|
||||
Needle = needle;
|
||||
MatchExact = matchExact;
|
||||
UseEndsWith = useEndsWith;
|
||||
this.Needle = needle;
|
||||
this.MatchExact = matchExact;
|
||||
this.UseEndsWith = useEndsWith;
|
||||
}
|
||||
|
||||
#region Matching
|
||||
@@ -43,23 +59,27 @@ namespace BinaryObjectScanner.Matching
|
||||
/// </summary>
|
||||
/// <param name="stack">List of strings to search for the given content</param>
|
||||
/// <returns>Tuple of success and matched item</returns>
|
||||
#if NET48
|
||||
public (bool, string) Match(IEnumerable<string> stack)
|
||||
#else
|
||||
public (bool, string?) Match(IEnumerable<string>? stack)
|
||||
#endif
|
||||
{
|
||||
// If either array is null or empty, we can't do anything
|
||||
if (stack == null || !stack.Any() || Needle == null || Needle.Length == 0)
|
||||
if (stack == null || !stack.Any() || this.Needle == null || this.Needle.Length == 0)
|
||||
return (false, null);
|
||||
|
||||
// Preprocess the needle, if necessary
|
||||
string procNeedle = MatchExact ? Needle : Needle.ToLowerInvariant();
|
||||
string procNeedle = this.MatchExact ? this.Needle : this.Needle.ToLowerInvariant();
|
||||
|
||||
foreach (string stackItem in stack)
|
||||
{
|
||||
// Preprocess the stack item, if necessary
|
||||
string procStackItem = MatchExact ? stackItem : stackItem.ToLowerInvariant();
|
||||
string procStackItem = this.MatchExact ? stackItem : stackItem.ToLowerInvariant();
|
||||
|
||||
if (UseEndsWith && procStackItem.EndsWith(procNeedle))
|
||||
if (this.UseEndsWith && procStackItem.EndsWith(procNeedle))
|
||||
return (true, stackItem);
|
||||
else if (!UseEndsWith && procStackItem.Contains(procNeedle))
|
||||
else if (!this.UseEndsWith && procStackItem.Contains(procNeedle))
|
||||
return (true, stackItem);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,11 @@ namespace BinaryObjectScanner.Matching
|
||||
/// in which case it will be appended to the protection name, or `null`,
|
||||
/// in which case it will cause the protection to be omitted.
|
||||
/// </remarks>
|
||||
public Func<string, IEnumerable<string>, string> GetVersion { get; set; }
|
||||
#if NET48
|
||||
public Func<string, IEnumerable<string>, string> GetVersion { get; private set; }
|
||||
#else
|
||||
public Func<string, IEnumerable<string>, string>? GetVersion { get; init; }
|
||||
#endif
|
||||
|
||||
#region Constructors
|
||||
|
||||
@@ -28,11 +32,19 @@ namespace BinaryObjectScanner.Matching
|
||||
public PathMatchSet(List<string> needles, string protectionName)
|
||||
: this(needles, null, protectionName) { }
|
||||
|
||||
#if NET48
|
||||
public PathMatchSet(string needle, Func<string, IEnumerable<string>, string> getVersion, string protectionName)
|
||||
: this(new List<string> { needle }, getVersion, protectionName) { }
|
||||
|
||||
public PathMatchSet(List<string> needles, Func<string, IEnumerable<string>, string> getVersion, string protectionName)
|
||||
: this(needles.Select(n => new PathMatch(n)).ToList(), getVersion, protectionName) { }
|
||||
#else
|
||||
public PathMatchSet(string needle, Func<string, IEnumerable<string>, string>? getVersion, string protectionName)
|
||||
: this(new List<string> { needle }, getVersion, protectionName) { }
|
||||
|
||||
public PathMatchSet(List<string> needles, Func<string, IEnumerable<string>, string>? getVersion, string protectionName)
|
||||
: this(needles.Select(n => new PathMatch(n)).ToList(), getVersion, protectionName) { }
|
||||
#endif
|
||||
|
||||
public PathMatchSet(PathMatch needle, string protectionName)
|
||||
: this(new List<PathMatch>() { needle }, null, protectionName) { }
|
||||
@@ -40,6 +52,7 @@ namespace BinaryObjectScanner.Matching
|
||||
public PathMatchSet(List<PathMatch> needles, string protectionName)
|
||||
: this(needles, null, protectionName) { }
|
||||
|
||||
#if NET48
|
||||
public PathMatchSet(PathMatch needle, Func<string, IEnumerable<string>, string> getVersion, string protectionName)
|
||||
: this(new List<PathMatch>() { needle }, getVersion, protectionName) { }
|
||||
|
||||
@@ -49,6 +62,17 @@ namespace BinaryObjectScanner.Matching
|
||||
GetVersion = getVersion;
|
||||
ProtectionName = protectionName;
|
||||
}
|
||||
#else
|
||||
public PathMatchSet(PathMatch needle, Func<string, IEnumerable<string>, string>? getVersion, string protectionName)
|
||||
: this(new List<PathMatch>() { needle }, getVersion, protectionName) { }
|
||||
|
||||
public PathMatchSet(List<PathMatch> needles, Func<string, IEnumerable<string>, string>? getVersion, string protectionName)
|
||||
{
|
||||
Matchers = needles;
|
||||
GetVersion = getVersion;
|
||||
ProtectionName = protectionName;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -58,7 +82,7 @@ namespace BinaryObjectScanner.Matching
|
||||
/// Determine whether all path matches pass
|
||||
/// </summary>
|
||||
/// <param name="stack">List of strings to try to match</param>
|
||||
/// <returns>Tuple of passing status and matching values</returns>
|
||||
/// <returns>Tuple of passing status and matching values</returns>
|
||||
public (bool, List<string>) MatchesAll(IEnumerable<string> stack)
|
||||
{
|
||||
// If no path matches are defined, we fail out
|
||||
@@ -71,8 +95,12 @@ namespace BinaryObjectScanner.Matching
|
||||
// Loop through all path matches and make sure all pass
|
||||
foreach (var pathMatch in Matchers)
|
||||
{
|
||||
#if NET48
|
||||
(bool match, string value) = pathMatch.Match(stack);
|
||||
if (!match)
|
||||
#else
|
||||
(bool match, string? value) = pathMatch.Match(stack);
|
||||
#endif
|
||||
if (!match || value == null)
|
||||
return (false, new List<string>());
|
||||
else
|
||||
values.Add(value);
|
||||
@@ -85,8 +113,12 @@ namespace BinaryObjectScanner.Matching
|
||||
/// Determine whether any path matches pass
|
||||
/// </summary>
|
||||
/// <param name="stack">List of strings to try to match</param>
|
||||
/// <returns>Tuple of passing status and first matching value</returns>
|
||||
/// <returns>Tuple of passing status and first matching value</returns>
|
||||
#if NET48
|
||||
public (bool, string) MatchesAny(IEnumerable<string> stack)
|
||||
#else
|
||||
public (bool, string?) MatchesAny(IEnumerable<string> stack)
|
||||
#endif
|
||||
{
|
||||
// If no path matches are defined, we fail out
|
||||
if (Matchers == null || !Matchers.Any())
|
||||
@@ -95,7 +127,11 @@ namespace BinaryObjectScanner.Matching
|
||||
// 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user