Overhaul matching extensions

This commit is contained in:
Matt Nadareski
2024-11-24 23:16:11 -05:00
parent 425f846e26
commit 9490dabbd6

View File

@@ -17,37 +17,52 @@ namespace SabreTools.Matching
/// <summary>
/// Find all positions of one array in another, if possible, if possible
/// </summary>
public static List<int> FindAllPositions(this byte[] stack, byte[]? needle, int start = 0, int end = -1)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
/// <param name="start">Optional starting position in the stack, defaults to 0</param>
/// <param name="end">Optional ending position in the stack, defaults to -1 (length of stack)</param>
public static List<int> FindAllPositions(this byte[] stack, byte[] needle, int start = 0, int end = -1)
{
// Convert the needle to a nullable byte array
byte?[]? nullableNeedle = null;
if (needle != null)
nullableNeedle = Array.ConvertAll(needle, b => (byte?)b);
byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b);
return FindAllPositions(stack, nullableNeedle, start, end);
}
/// <summary>
/// Find all positions of one array in another, if possible, if possible
/// </summary>
public static List<int> FindAllPositions(this byte[] stack, byte?[]? needle, int start = 0, int end = -1)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
/// <param name="start">Optional starting position in the stack, defaults to 0</param>
/// <param name="end">Optional ending position in the stack, defaults to -1 (length of stack)</param>
public static List<int> FindAllPositions(this byte[] stack, byte?[] needle, int start = 0, int end = -1)
{
// Get the outgoing list
List<int> positions = [];
// Initialize the loop variables
int lastPosition = start;
var matcher = new ContentMatch(needle, end: end);
// Validate the start and end values
if (start < 0 || start >= stack.Length)
return positions;
if (end < -1 || (end != -1 && end < start) || end > stack.Length)
return positions;
// Loop over and get all positions
while (true)
// Normalize the end value, if necessary
if (end == -1)
end = stack.Length;
// Loop while there is data to check
while (start < end)
{
matcher.Start = lastPosition;
lastPosition = matcher.Match(stack, false);
if (lastPosition < 0)
// Create a new matcher for this segment
var matcher = new ContentMatch(needle, start, end);
// Get the next matching position
int position = matcher.Match(stack, reverse: false);
if (position < 0)
break;
positions.Add(lastPosition);
// Append the position and reset the start index
positions.Add(position);
start = position;
}
return positions;
@@ -56,115 +71,111 @@ namespace SabreTools.Matching
/// <summary>
/// Find the first position of one array in another, if possible
/// </summary>
public static bool FirstPosition(this byte[] stack, byte[]? needle, out int position, int start = 0, int end = -1)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
/// <param name="start">Optional starting position in the stack, defaults to 0</param>
/// <param name="end">Optional ending position in the stack, defaults to -1 (length of stack)</param>
public static int FirstPosition(this byte[] stack, byte[] needle, int start = 0, int end = -1)
{
// Convert the needle to a nullable byte array
byte?[]? nullableNeedle = null;
if (needle != null)
nullableNeedle = Array.ConvertAll(needle, b => (byte?)b);
return FirstPosition(stack, nullableNeedle, out position, start, end);
byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b);
return FirstPosition(stack, nullableNeedle, start, end);
}
/// <summary>
/// Find the first position of one array in another, if possible
/// </summary>
public static bool FirstPosition(this byte[] stack, byte?[]? needle, out int position, int start = 0, int end = -1)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
/// <param name="start">Optional starting position in the stack, defaults to 0</param>
/// <param name="end">Optional ending position in the stack, defaults to -1 (length of stack)</param>
public static int FirstPosition(this byte[] stack, byte?[] needle, int start = 0, int end = -1)
{
var matcher = new ContentMatch(needle, start, end);
position = matcher.Match(stack, false);
return position >= 0;
return matcher.Match(stack, reverse: false);
}
/// <summary>
/// Find the last position of one array in another, if possible
/// </summary>
public static bool LastPosition(this byte[] stack, byte[]? needle, out int position, int start = 0, int end = -1)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
/// <param name="start">Optional starting position in the stack, defaults to 0</param>
/// <param name="end">Optional ending position in the stack, defaults to -1 (length of stack)</param>
public static int LastPosition(this byte[] stack, byte[] needle, int start = 0, int end = -1)
{
// Convert the needle to a nullable byte array
byte?[]? nullableNeedle = null;
if (needle != null)
nullableNeedle = Array.ConvertAll(needle, b => (byte?)b);
return LastPosition(stack, nullableNeedle, out position, start, end);
byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b);
return LastPosition(stack, nullableNeedle, start, end);
}
/// <summary>
/// Find the last position of one array in another, if possible
/// </summary>
public static bool LastPosition(this byte[] stack, byte?[]? needle, out int position, int start = 0, int end = -1)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
/// <param name="start">Optional starting position in the stack, defaults to 0</param>
/// <param name="end">Optional ending position in the stack, defaults to -1 (length of stack)</param>
public static int LastPosition(this byte[] stack, byte?[] needle, int start = 0, int end = -1)
{
var matcher = new ContentMatch(needle, start, end);
position = matcher.Match(stack, true);
return position >= 0;
return matcher.Match(stack, reverse: true);
}
/// <summary>
/// See if a byte array starts with another
/// Check if a byte array starts with another
/// </summary>
public static bool StartsWith(this byte[] stack, byte[]? needle, bool exact = false)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
public static bool StartsWith(this byte[] stack, byte[] needle)
{
// If we have any invalid inputs, we return false
if (needle == null
|| stack.Length == 0 || needle.Length == 0
|| needle.Length > stack.Length
|| (exact && stack.Length != needle.Length))
{
return false;
}
return FirstPosition(stack, needle, out int _, start: 0, end: 1);
byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b);
return StartsWith(stack, nullableNeedle);
}
/// <summary>
/// See if a byte array starts with another
/// Check if a byte array starts with another
/// </summary>
public static bool StartsWith(this byte[] stack, byte?[]? needle, bool exact = false)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
public static bool StartsWith(this byte[] stack, byte?[] needle)
{
// If we have any invalid inputs, we return false
if (needle == null
|| stack.Length == 0 || needle.Length == 0
|| needle.Length > stack.Length
|| (exact && stack.Length != needle.Length))
{
// If either the stack or needle are 0-length
if (stack.Length == 0 || needle.Length == 0)
return false;
}
return FirstPosition(stack, needle, out int _, start: 0, end: 1);
// If the needle is longer than the stack
if (needle.Length > stack.Length)
return false;
return FirstPosition(stack, needle, start: 0, end: 1) > -1;
}
/// <summary>
/// See if a byte array ends with another
/// Check if a byte array ends with another
/// </summary>
public static bool EndsWith(this byte[] stack, byte[]? needle, bool exact = false)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
public static bool EndsWith(this byte[] stack, byte[] needle)
{
// If we have any invalid inputs, we return false
if (needle == null
|| stack.Length == 0 || needle.Length == 0
|| needle.Length > stack.Length
|| (exact && stack.Length != needle.Length))
{
return false;
}
return FirstPosition(stack, needle, out int _, start: stack.Length - needle.Length);
byte?[] nullableNeedle = Array.ConvertAll(needle, b => (byte?)b);
return EndsWith(stack, nullableNeedle);
}
/// <summary>
/// See if a byte array ends with another
/// Check if a byte array ends with another
/// </summary>
public static bool EndsWith(this byte[] stack, byte?[]? needle, bool exact = false)
/// <param name="stack">Byte array to search within</param>
/// <param name="needle">Byte array representing the search value</param>
public static bool EndsWith(this byte[] stack, byte?[] needle)
{
// If we have any invalid inputs, we return false
if (needle == null
|| stack.Length == 0 || needle.Length == 0
|| needle.Length > stack.Length
|| (exact && stack.Length != needle.Length))
{
// If either the stack or needle are 0-length
if (stack.Length == 0 || needle.Length == 0)
return false;
}
return FirstPosition(stack, needle, out int _, start: stack.Length - needle.Length);
// If the needle is longer than the stack
if (needle.Length > stack.Length)
return false;
return FirstPosition(stack, needle, start: stack.Length - needle.Length) > -1;
}
}
}