mirror of
https://github.com/SabreTools/BinaryObjectScanner.git
synced 2026-10-01 11:12:02 +00:00
Get rid of code duplication
This commit is contained in:
@@ -1,356 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using BurnOutSharp.Matching;
|
||||
|
||||
namespace BurnOutSharp.Tools
|
||||
{
|
||||
internal static class Extensions
|
||||
{
|
||||
#region Byte Arrays
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static byte ReadByte(this byte[] content, ref int offset)
|
||||
{
|
||||
return content[offset++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte array and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static byte[] ReadBytes(this byte[] content, ref int offset, int count)
|
||||
{
|
||||
byte[] buffer = new byte[count];
|
||||
Array.Copy(content, offset, buffer, 0, Math.Min(count, content.Length - offset));
|
||||
offset += count;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a char and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static char ReadChar(this byte[] content, ref int offset)
|
||||
{
|
||||
return (char)content[offset++];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a character array and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static char[] ReadChars(this byte[] content, ref int offset, int count) => content.ReadChars(ref offset, count, Encoding.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Read a character array and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static char[] ReadChars(this byte[] content, ref int offset, int count, Encoding encoding)
|
||||
{
|
||||
// TODO: Fix the code below to make it work with byte arrays and not streams
|
||||
return null;
|
||||
|
||||
// byte[] buffer = new byte[count];
|
||||
// stream.Read(buffer, 0, count);
|
||||
// return encoding.GetString(buffer).ToCharArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a short and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static short ReadInt16(this byte[] content, ref int offset)
|
||||
{
|
||||
short value = BitConverter.ToInt16(content, offset);
|
||||
offset += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a ushort and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static ushort ReadUInt16(this byte[] content, ref int offset)
|
||||
{
|
||||
ushort value = BitConverter.ToUInt16(content, offset);
|
||||
offset += 2;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a int and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static int ReadInt32(this byte[] content, ref int offset)
|
||||
{
|
||||
int value = BitConverter.ToInt32(content, offset);
|
||||
offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a uint and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static uint ReadUInt32(this byte[] content, ref int offset)
|
||||
{
|
||||
uint value = BitConverter.ToUInt32(content, offset);
|
||||
offset += 4;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a long and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static long ReadInt64(this byte[] content, ref int offset)
|
||||
{
|
||||
long value = BitConverter.ToInt64(content, offset);
|
||||
offset += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a ulong and increment the pointer to an array
|
||||
/// </summary>
|
||||
public static ulong ReadUInt64(this byte[] content, ref int offset)
|
||||
{
|
||||
ulong value = BitConverter.ToUInt64(content, offset);
|
||||
offset += 8;
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated string from the stream
|
||||
/// </summary>
|
||||
public static string ReadString(this byte[] content, ref int offset) => content.ReadString(ref offset, Encoding.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated string from the stream
|
||||
/// </summary>
|
||||
public static string ReadString(this byte[] content, ref int offset, Encoding encoding)
|
||||
{
|
||||
if (offset >= content.Length)
|
||||
return null;
|
||||
|
||||
byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' });
|
||||
int charWidth = nullTerminator.Length;
|
||||
|
||||
List<char> keyChars = new List<char>();
|
||||
while (offset < content.Length)
|
||||
{
|
||||
char c = encoding.GetChars(content, offset, charWidth)[0];
|
||||
keyChars.Add(c);
|
||||
offset += charWidth;
|
||||
|
||||
if (c == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
return new string(keyChars.ToArray()).TrimEnd('\0');
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
// Get the outgoing list
|
||||
List<int> positions = new List<int>();
|
||||
|
||||
// Initialize the loop variables
|
||||
bool found = true;
|
||||
int lastPosition = start;
|
||||
var matcher = new ContentMatch(needle, end: end);
|
||||
|
||||
// Loop over and get all positions
|
||||
while (found)
|
||||
{
|
||||
matcher.Start = lastPosition;
|
||||
(found, lastPosition) = matcher.Match(stack, false);
|
||||
if (found)
|
||||
positions.Add(lastPosition);
|
||||
}
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
byte?[] nullableNeedle = needle != null ? needle.Select(b => (byte?)b).ToArray() : null;
|
||||
return stack.FirstPosition(nullableNeedle, out position, 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)
|
||||
{
|
||||
var matcher = new ContentMatch(needle, start, end);
|
||||
(bool found, int foundPosition) = matcher.Match(stack, false);
|
||||
position = foundPosition;
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
var matcher = new ContentMatch(needle, start, end);
|
||||
(bool found, int foundPosition) = matcher.Match(stack, true);
|
||||
position = foundPosition;
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See if a byte array starts with another
|
||||
/// </summary>
|
||||
public static bool StartsWith(this byte[] stack, byte?[] needle)
|
||||
{
|
||||
return stack.FirstPosition(needle, out int _, start: 0, end: 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See if a byte array ends with another
|
||||
/// </summary>
|
||||
public static bool EndsWith(this byte[] stack, byte?[] needle)
|
||||
{
|
||||
return stack.FirstPosition(needle, out int _, start: stack.Length - needle.Length);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Streams
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte from the stream
|
||||
/// </summary>
|
||||
public static byte ReadByteValue(this Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[1];
|
||||
stream.Read(buffer, 0, 1);
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a byte array from the stream
|
||||
/// </summary>
|
||||
public static byte[] ReadBytes(this Stream stream, int count)
|
||||
{
|
||||
byte[] buffer = new byte[count];
|
||||
stream.Read(buffer, 0, count);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a character from the stream
|
||||
/// </summary>
|
||||
public static char ReadChar(this Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[1];
|
||||
stream.Read(buffer, 0, 1);
|
||||
return (char)buffer[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a character array from the stream
|
||||
/// </summary>
|
||||
public static char[] ReadChars(this Stream stream, int count) => stream.ReadChars(count, Encoding.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Read a character array from the stream
|
||||
/// </summary>
|
||||
public static char[] ReadChars(this Stream stream, int count, Encoding encoding)
|
||||
{
|
||||
byte[] buffer = new byte[count];
|
||||
stream.Read(buffer, 0, count);
|
||||
return encoding.GetString(buffer).ToCharArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a short from the stream
|
||||
/// </summary>
|
||||
public static short ReadInt16(this Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[2];
|
||||
stream.Read(buffer, 0, 2);
|
||||
return BitConverter.ToInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a ushort from the stream
|
||||
/// </summary>
|
||||
public static ushort ReadUInt16(this Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[2];
|
||||
stream.Read(buffer, 0, 2);
|
||||
return BitConverter.ToUInt16(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read an int from the stream
|
||||
/// </summary>
|
||||
public static int ReadInt32(this Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[4];
|
||||
stream.Read(buffer, 0, 4);
|
||||
return BitConverter.ToInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a uint from the stream
|
||||
/// </summary>
|
||||
public static uint ReadUInt32(this Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[4];
|
||||
stream.Read(buffer, 0, 4);
|
||||
return BitConverter.ToUInt32(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a long from the stream
|
||||
/// </summary>
|
||||
public static long ReadInt64(this Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[8];
|
||||
stream.Read(buffer, 0, 8);
|
||||
return BitConverter.ToInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a ulong from the stream
|
||||
/// </summary>
|
||||
public static ulong ReadUInt64(this Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[8];
|
||||
stream.Read(buffer, 0, 8);
|
||||
return BitConverter.ToUInt64(buffer, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated string from the stream
|
||||
/// </summary>
|
||||
public static string ReadString(this Stream stream) => stream.ReadString(Encoding.Default);
|
||||
|
||||
/// <summary>
|
||||
/// Read a null-terminated string from the stream
|
||||
/// </summary>
|
||||
public static string ReadString(this Stream stream, Encoding encoding)
|
||||
{
|
||||
byte[] nullTerminator = encoding.GetBytes(new char[] { '\0' });
|
||||
int charWidth = nullTerminator.Length;
|
||||
|
||||
List<byte> tempBuffer = new List<byte>();
|
||||
|
||||
byte[] buffer = new byte[charWidth];
|
||||
while (stream.Read(buffer, 0, charWidth) != 0 && !buffer.SequenceEqual(nullTerminator))
|
||||
{
|
||||
tempBuffer.AddRange(buffer);
|
||||
}
|
||||
|
||||
return encoding.GetString(tempBuffer.ToArray());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,182 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using BurnOutSharp.Interfaces;
|
||||
using BurnOutSharp.Matching;
|
||||
using BurnOutSharp.Wrappers;
|
||||
|
||||
namespace BurnOutSharp.Tools
|
||||
{
|
||||
internal static class Utilities
|
||||
{
|
||||
#region Dictionary Manipulation
|
||||
|
||||
/// <summary>
|
||||
/// Append one result to a results dictionary
|
||||
/// </summary>
|
||||
/// <param name="original">Dictionary to append to</param>
|
||||
/// <param name="key">Key to add information to</param>
|
||||
/// <param name="value">String value to add</param>
|
||||
public static void AppendToDictionary(ConcurrentDictionary<string, ConcurrentQueue<string>> original, string key, string value)
|
||||
{
|
||||
// If the value is empty, don't add it
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
return;
|
||||
|
||||
var values = new ConcurrentQueue<string>();
|
||||
values.Enqueue(value);
|
||||
AppendToDictionary(original, key, values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append one result to a results dictionary
|
||||
/// </summary>
|
||||
/// <param name="original">Dictionary to append to</param>
|
||||
/// <param name="key">Key to add information to</param>
|
||||
/// <param name="value">String value to add</param>
|
||||
public static void AppendToDictionary(ConcurrentDictionary<string, ConcurrentQueue<string>> original, string key, ConcurrentQueue<string> values)
|
||||
{
|
||||
// If the dictionary is null, just return
|
||||
if (original == null)
|
||||
return;
|
||||
|
||||
// Use a placeholder value if the key is null
|
||||
key = key ?? "NO FILENAME";
|
||||
|
||||
// Add the key if needed and then append the lists
|
||||
original.TryAdd(key, new ConcurrentQueue<string>());
|
||||
original[key].AddRange(values);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append one results dictionary to another
|
||||
/// </summary>
|
||||
/// <param name="original">Dictionary to append to</param>
|
||||
/// <param name="addition">Dictionary to pull from</param>
|
||||
public static void AppendToDictionary(ConcurrentDictionary<string, ConcurrentQueue<string>> original, ConcurrentDictionary<string, ConcurrentQueue<string>> addition)
|
||||
{
|
||||
// If either dictionary is missing, just return
|
||||
if (original == null || addition == null)
|
||||
return;
|
||||
|
||||
// Loop through each of the addition keys and add accordingly
|
||||
foreach (string key in addition.Keys)
|
||||
{
|
||||
original.TryAdd(key, new ConcurrentQueue<string>());
|
||||
original[key].AddRange(addition[key]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove empty or null keys from a results dictionary
|
||||
/// </summary>
|
||||
/// <param name="original">Dictionary to clean</param>
|
||||
public static void ClearEmptyKeys(ConcurrentDictionary<string, ConcurrentQueue<string>> original)
|
||||
{
|
||||
// If the dictionary is missing, we can't do anything
|
||||
if (original == null)
|
||||
return;
|
||||
|
||||
// Get a list of all of the keys
|
||||
var keys = original.Keys.ToList();
|
||||
|
||||
// Iterate and reset keys
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
// Get the current key
|
||||
string key = keys[i];
|
||||
|
||||
// If the key is empty, remove it
|
||||
if (original[key] == null || !original[key].Any())
|
||||
original.TryRemove(key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepend a parent path from dictionary keys, if possible
|
||||
/// </summary>
|
||||
/// <param name="original">Dictionary to strip values from</param>
|
||||
/// <param name="pathToPrepend">Path to strip from the keys</param>
|
||||
public static void PrependToKeys(ConcurrentDictionary<string, ConcurrentQueue<string>> original, string pathToPrepend)
|
||||
{
|
||||
// If the dictionary is missing, we can't do anything
|
||||
if (original == null)
|
||||
return;
|
||||
|
||||
// Use a placeholder value if the path is null
|
||||
pathToPrepend = (pathToPrepend ?? "ARCHIVE").TrimEnd(Path.DirectorySeparatorChar);
|
||||
|
||||
// Get a list of all of the keys
|
||||
var keys = original.Keys.ToList();
|
||||
|
||||
// Iterate and reset keys
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
// Get the current key
|
||||
string currentKey = keys[i];
|
||||
|
||||
// Otherwise, get the new key name and transfer over
|
||||
string newKey = $"{pathToPrepend}{Path.DirectorySeparatorChar}{currentKey.Trim(Path.DirectorySeparatorChar)}";
|
||||
original[newKey] = original[currentKey];
|
||||
original.TryRemove(currentKey, out _);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strip a parent path from dictionary keys, if possible
|
||||
/// </summary>
|
||||
/// <param name="original">Dictionary to strip values from</param>
|
||||
/// <param name="pathToStrip">Path to strip from the keys</param>
|
||||
public static void StripFromKeys(ConcurrentDictionary<string, ConcurrentQueue<string>> original, string pathToStrip)
|
||||
{
|
||||
// If either is missing, we can't do anything
|
||||
if (original == null || string.IsNullOrEmpty(pathToStrip))
|
||||
return;
|
||||
|
||||
// Get a list of all of the keys
|
||||
var keys = original.Keys.ToList();
|
||||
|
||||
// Iterate and reset keys
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
// Get the current key
|
||||
string currentKey = keys[i];
|
||||
|
||||
// If the key doesn't start with the path, don't touch it
|
||||
if (!currentKey.StartsWith(pathToStrip, StringComparison.OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
// Otherwise, get the new key name and transfer over
|
||||
string newKey = currentKey.Substring(pathToStrip.Length);
|
||||
original[newKey] = original[currentKey];
|
||||
original.TryRemove(currentKey, out _);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Concurrent Manipulation
|
||||
|
||||
/// <summary>
|
||||
/// Add a range of values from one queue to another
|
||||
/// </summary>
|
||||
/// <param name="original">Queue to add data to</param>
|
||||
/// <param name="values">Queue to get data from</param>
|
||||
public static void AddRange(this ConcurrentQueue<string> original, ConcurrentQueue<string> values)
|
||||
{
|
||||
while (!values.IsEmpty)
|
||||
{
|
||||
if (!values.TryDequeue(out string value))
|
||||
return;
|
||||
|
||||
original.Enqueue(value);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region File Types
|
||||
|
||||
/// <summary>
|
||||
@@ -745,51 +577,6 @@ namespace BurnOutSharp.Tools
|
||||
|
||||
#endregion
|
||||
|
||||
#region Executable Information
|
||||
|
||||
/// <summary>
|
||||
/// Get the SHA1 hash of a file, if possible
|
||||
/// </summary>
|
||||
/// <param name="path">Path to the file to be hashed</param>
|
||||
/// <returns>SHA1 hash as a string on success, null on error</returns>
|
||||
public static string GetFileSHA1(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
SHA1 sha1 = SHA1.Create();
|
||||
using (Stream fileStream = File.OpenRead(path))
|
||||
{
|
||||
byte[] buffer = new byte[32768];
|
||||
while (true)
|
||||
{
|
||||
int bytesRead = fileStream.Read(buffer, 0, 32768);
|
||||
if (bytesRead == 32768)
|
||||
{
|
||||
sha1.TransformBlock(buffer, 0, bytesRead, null, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sha1.TransformFinalBlock(buffer, 0, bytesRead);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string hash = BitConverter.ToString(sha1.Hash);
|
||||
hash = hash.Replace("-", string.Empty);
|
||||
return hash;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Wrappers for Matchers
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user