diff --git a/ReClass.NET/MemoryScanner/BytePattern.cs b/ReClass.NET/MemoryScanner/BytePattern.cs index 414d2494..46335046 100644 --- a/ReClass.NET/MemoryScanner/BytePattern.cs +++ b/ReClass.NET/MemoryScanner/BytePattern.cs @@ -5,7 +5,6 @@ using System.Linq; using System.Text; using ReClassNET.Extensions; -using ReClassNET.Util; namespace ReClassNET.MemoryScanner { @@ -202,6 +201,27 @@ public static BytePattern From(IEnumerable> data) return pattern; } + // TODO: Use System.Span after it is available + /*/// + /// Tests if the provided byte array matches the byte pattern at the provided index. + /// + /// The byte array to be compared. + /// True if the pattern matches, false if they are not. + public bool Equals(Span data) + { + Contract.Requires(data != null); + + for (var j = 0; j < pattern.Count; ++j) + { + if (!pattern[j].Equals(data[j])) + { + return false; + } + } + + return true; + }*/ + /// /// Tests if the provided byte array matches the byte pattern at the provided index. /// @@ -223,6 +243,21 @@ public bool Equals(byte[] data, int index) return true; } + public unsafe bool Equals(byte* data) + { + Contract.Requires(data != null); + + for (var j = 0; j < pattern.Count; ++j) + { + if (!pattern[j].Equals(*(data + j))) + { + return false; + } + } + + return true; + } + /// /// Converts this to a byte array. /// diff --git a/ReClass.NET/MemoryScanner/Comparer/ArrayOfBytesMemoryComparer.cs b/ReClass.NET/MemoryScanner/Comparer/ArrayOfBytesMemoryComparer.cs index e7e2bcbc..03f3c0d3 100644 --- a/ReClass.NET/MemoryScanner/Comparer/ArrayOfBytesMemoryComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/ArrayOfBytesMemoryComparer.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using System.Diagnostics.Contracts; namespace ReClassNET.MemoryScanner.Comparer @@ -31,7 +30,7 @@ public ArrayOfBytesMemoryComparer(byte[] pattern) byteArray = pattern; } - public bool Compare(byte[] data, int index, out ScanResult result) + public unsafe bool Compare(byte* data, out ScanResult result) { result = null; @@ -39,31 +38,39 @@ public bool Compare(byte[] data, int index, out ScanResult result) { for (var i = 0; i < byteArray.Length; ++i) { - if (data[index + i] != byteArray[i]) + if (*(data + i) != byteArray[i]) { return false; } } } - else if (!bytePattern.Equals(data, index)) + // TODO: Use System.Span after it is available + //else if (!bytePattern.Equals(new Span(data, ValueSize))) + else if (!bytePattern.Equals(data)) { return false; } var temp = new byte[ValueSize]; - Array.Copy(data, index, temp, 0, temp.Length); + fixed (byte* cpy = &temp[0]) + { + for (var i = 0; i < ValueSize; ++i) + { + *(cpy + i) = *(data + i); + } + } result = new ArrayOfBytesScanResult(temp); return true; } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { #if DEBUG Debug.Assert(previous is ArrayOfBytesScanResult); #endif - return Compare(data, index, out result); + return Compare(data, out result); } } } diff --git a/ReClass.NET/MemoryScanner/Comparer/ByteMemoryComparer.cs b/ReClass.NET/MemoryScanner/Comparer/ByteMemoryComparer.cs index 4d175d9f..a79672d1 100644 --- a/ReClass.NET/MemoryScanner/Comparer/ByteMemoryComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/ByteMemoryComparer.cs @@ -26,11 +26,11 @@ public ByteMemoryComparer(ScanCompareType compareType, byte value1, byte value2) Value2 = value2; } - public bool Compare(byte[] data, int index, out ScanResult result) + public unsafe bool Compare(byte* data, out ScanResult result) { result = null; - var value = data[index]; + var value = *data; bool IsMatch() { @@ -69,20 +69,20 @@ bool IsMatch() return true; } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { #if DEBUG Debug.Assert(previous is ByteScanResult); #endif - return Compare(data, index, (ByteScanResult)previous, out result); + return Compare(data, (ByteScanResult)previous, out result); } - public bool Compare(byte[] data, int index, ByteScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ByteScanResult previous, out ScanResult result) { result = null; - var value = data[index]; + var value = *data; bool IsMatch() { diff --git a/ReClass.NET/MemoryScanner/Comparer/DoubleMemoryComparer.cs b/ReClass.NET/MemoryScanner/Comparer/DoubleMemoryComparer.cs index 56c50164..266addc7 100644 --- a/ReClass.NET/MemoryScanner/Comparer/DoubleMemoryComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/DoubleMemoryComparer.cs @@ -55,11 +55,11 @@ private bool CheckRoundedEquality(double value) } } - public bool Compare(byte[] data, int index, out ScanResult result) + public unsafe bool Compare(byte* data, out ScanResult result) { result = null; - var value = BitConverter.ToDouble(data, index); + var value = *(double*)data; bool IsMatch() { @@ -98,20 +98,20 @@ bool IsMatch() return true; } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { #if DEBUG Debug.Assert(previous is DoubleScanResult); #endif - return Compare(data, index, (DoubleScanResult)previous, out result); + return Compare(data, (DoubleScanResult)previous, out result); } - public bool Compare(byte[] data, int index, DoubleScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, DoubleScanResult previous, out ScanResult result) { result = null; - var value = BitConverter.ToDouble(data, index); + var value = *(double*)data; bool IsMatch() { diff --git a/ReClass.NET/MemoryScanner/Comparer/FloatMemoryComparer.cs b/ReClass.NET/MemoryScanner/Comparer/FloatMemoryComparer.cs index 52e96974..86db6bf8 100644 --- a/ReClass.NET/MemoryScanner/Comparer/FloatMemoryComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/FloatMemoryComparer.cs @@ -55,11 +55,11 @@ private bool CheckRoundedEquality(float value) } } - public bool Compare(byte[] data, int index, out ScanResult result) + public unsafe bool Compare(byte* data, out ScanResult result) { result = null; - var value = BitConverter.ToSingle(data, index); + var value = *(float*)data; bool IsMatch() { @@ -98,20 +98,20 @@ bool IsMatch() return true; } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { #if DEBUG Debug.Assert(previous is FloatScanResult); #endif - return Compare(data, index, (FloatScanResult)previous, out result); + return Compare(data, (FloatScanResult)previous, out result); } - public bool Compare(byte[] data, int index, FloatScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, FloatScanResult previous, out ScanResult result) { result = null; - var value = BitConverter.ToSingle(data, index); + var value = *(float*)data; bool IsMatch() { diff --git a/ReClass.NET/MemoryScanner/Comparer/IScanComparer.cs b/ReClass.NET/MemoryScanner/Comparer/IScanComparer.cs index 35be65f5..8537334f 100644 --- a/ReClass.NET/MemoryScanner/Comparer/IScanComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/IScanComparer.cs @@ -13,21 +13,19 @@ public interface IScanComparer /// Compares the data at the provided index to the current . /// /// The byte array to be compared. - /// The index into the byte array. /// [out] The scan result if the matched. /// True if matched. - bool Compare(byte[] data, int index, out ScanResult result); + unsafe bool Compare(byte* data, out ScanResult result); /// /// Compares the data at the provided index to the current . /// The previous results may be used. /// /// The byte array to be compared. - /// The index into the byte array. /// Scan result to be compared. /// [out] The scan result if the matched. /// True if matched. - bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result); + unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result); } [ContractClassFor(typeof(IScanComparer))] @@ -44,18 +42,13 @@ public int ValueSize throw new NotImplementedException(); } } - public bool Compare(byte[] data, int index, out ScanResult result) + public unsafe bool Compare(byte* data, out ScanResult result) { - Contract.Requires(data != null); - Contract.Requires(index >= 0); - throw new NotImplementedException(); } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { - Contract.Requires(data != null); - Contract.Requires(index >= 0); Contract.Requires(previous != null); throw new NotImplementedException(); diff --git a/ReClass.NET/MemoryScanner/Comparer/IntegerMemoryComparer.cs b/ReClass.NET/MemoryScanner/Comparer/IntegerMemoryComparer.cs index 3a8b97ba..e7505916 100644 --- a/ReClass.NET/MemoryScanner/Comparer/IntegerMemoryComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/IntegerMemoryComparer.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using ReClassNET.Util; namespace ReClassNET.MemoryScanner.Comparer @@ -27,11 +26,11 @@ public IntegerMemoryComparer(ScanCompareType compareType, int value1, int value2 Value2 = value2; } - public bool Compare(byte[] data, int index, out ScanResult result) + public unsafe bool Compare(byte* data, out ScanResult result) { result = null; - var value = BitConverter.ToInt32(data, index); + var value = *(int*)data; bool IsMatch() { @@ -70,20 +69,20 @@ bool IsMatch() return true; } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { #if DEBUG Debug.Assert(previous is IntegerScanResult); #endif - return Compare(data, index, (IntegerScanResult)previous, out result); + return Compare(data, (IntegerScanResult)previous, out result); } - public bool Compare(byte[] data, int index, IntegerScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, IntegerScanResult previous, out ScanResult result) { result = null; - var value = BitConverter.ToInt32(data, index); + var value = *(int*)data; bool IsMatch() { diff --git a/ReClass.NET/MemoryScanner/Comparer/LongMemoryComparer.cs b/ReClass.NET/MemoryScanner/Comparer/LongMemoryComparer.cs index 662f1a99..b3e9d992 100644 --- a/ReClass.NET/MemoryScanner/Comparer/LongMemoryComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/LongMemoryComparer.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using ReClassNET.Util; namespace ReClassNET.MemoryScanner.Comparer @@ -27,11 +26,11 @@ public LongMemoryComparer(ScanCompareType compareType, long value1, long value2) Value2 = value2; } - public bool Compare(byte[] data, int index, out ScanResult result) + public unsafe bool Compare(byte* data, out ScanResult result) { result = null; - var value = BitConverter.ToInt64(data, index); + var value = *(long*)data; bool IsMatch() { @@ -70,20 +69,20 @@ bool IsMatch() return true; } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { #if DEBUG Debug.Assert(previous is LongScanResult); #endif - return Compare(data, index, (LongScanResult)previous, out result); + return Compare(data, (LongScanResult)previous, out result); } - public bool Compare(byte[] data, int index, LongScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, LongScanResult previous, out ScanResult result) { result = null; - var value = BitConverter.ToInt64(data, index); + var value = *(long*)data; bool IsMatch() { diff --git a/ReClass.NET/MemoryScanner/Comparer/ShortMemoryComparer.cs b/ReClass.NET/MemoryScanner/Comparer/ShortMemoryComparer.cs index 8e541704..08a97bb0 100644 --- a/ReClass.NET/MemoryScanner/Comparer/ShortMemoryComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/ShortMemoryComparer.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using ReClassNET.Util; namespace ReClassNET.MemoryScanner.Comparer @@ -27,11 +26,11 @@ public ShortMemoryComparer(ScanCompareType compareType, short value1, short valu Value2 = value2; } - public bool Compare(byte[] data, int index, out ScanResult result) + public unsafe bool Compare(byte* data, out ScanResult result) { result = null; - var value = BitConverter.ToInt16(data, index); + var value = *(short*)data; bool IsMatch() { @@ -70,20 +69,20 @@ bool IsMatch() return true; } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { #if DEBUG Debug.Assert(previous is ShortScanResult); #endif - return Compare(data, index, (ShortScanResult)previous, out result); + return Compare(data, (ShortScanResult)previous, out result); } - public bool Compare(byte[] data, int index, ShortScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ShortScanResult previous, out ScanResult result) { result = null; - var value = BitConverter.ToInt16(data, index); + var value = *(short*)data; bool IsMatch() { diff --git a/ReClass.NET/MemoryScanner/Comparer/StringMemoryComparer.cs b/ReClass.NET/MemoryScanner/Comparer/StringMemoryComparer.cs index 44b958ed..40b847fe 100644 --- a/ReClass.NET/MemoryScanner/Comparer/StringMemoryComparer.cs +++ b/ReClass.NET/MemoryScanner/Comparer/StringMemoryComparer.cs @@ -1,50 +1,102 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; +using System.Linq; using System.Text; -using ReClassNET.Extensions; -using ReClassNET.Util; namespace ReClassNET.MemoryScanner.Comparer { public class StringMemoryComparer : IScanComparer { public ScanCompareType CompareType => ScanCompareType.Equal; - public bool CaseSensitive { get; } + public bool IsCaseSensitive { get; } public Encoding Encoding { get; } public string Value { get; } + public char[] Chars { get; } public int ValueSize { get; } - public StringMemoryComparer(string value, Encoding encoding, bool caseSensitive) + private unsafe delegate char GetCharacter(byte* data, int index); + + private readonly GetCharacter getCharacter; + + public StringMemoryComparer(string value, Encoding encoding, bool isCaseSensitive) { - Value = value; + IsCaseSensitive = isCaseSensitive; Encoding = encoding; - CaseSensitive = caseSensitive; - ValueSize = Value.Length * Encoding.GetSimpleByteCountPerChar(); + Value = value; + Chars = value.Select(c => isCaseSensitive ? c : char.ToUpperInvariant(c)).ToArray(); + ValueSize = Encoding.GetByteCount(value); + + unsafe + { + getCharacter = Encoding == Encoding.UTF8 + ? IsCaseSensitive + ? (GetCharacter)GetCharacterCaseSensitiveUtf8 + : GetCharacterCaseInsensitiveUtf8 + : Encoding == Encoding.Unicode + ? IsCaseSensitive + ? (GetCharacter)GetCharacterCaseSensitiveUtf16 + : GetCharacterCaseInsensitiveUtf16 + : IsCaseSensitive + ? (GetCharacter)GetCharacterCaseSensitiveUtf32 + : GetCharacterCaseInsensitiveUtf32; + } } - public bool Compare(byte[] data, int index, out ScanResult result) + private static unsafe char GetCharacterCaseSensitiveUtf8(byte* data, int index) { - result = null; + return (char)*(data + index); + } + + private static unsafe char GetCharacterCaseInsensitiveUtf8(byte* data, int index) + { + return char.ToUpperInvariant(GetCharacterCaseSensitiveUtf8(data, index)); + } + + private static unsafe char GetCharacterCaseSensitiveUtf16(byte* data, int index) + { + return *((char*)data + index); + } - var value = Encoding.GetString(data, index, Value.Length); + private static unsafe char GetCharacterCaseInsensitiveUtf16(byte* data, int index) + { + return char.ToUpperInvariant(GetCharacterCaseSensitiveUtf16(data, index)); + } + + private static unsafe char GetCharacterCaseSensitiveUtf32(byte* data, int index) + { + var dst = stackalloc char[1]; + Encoding.UTF32.GetChars(data + index * sizeof(int), 4, dst, 1); + return *dst; + } + + private static unsafe char GetCharacterCaseInsensitiveUtf32(byte* data, int index) + { + return char.ToUpperInvariant(GetCharacterCaseSensitiveUtf32(data, index)); + } + + public unsafe bool Compare(byte* data, out ScanResult result) + { + result = null; - if (!Value.Equals(value, CaseSensitive ? StringComparison.InvariantCulture : StringComparison.InvariantCultureIgnoreCase)) + for (var i = 0; i < Chars.Length; ++i) { - return false; + if (Chars[i] != getCharacter(data, i)) + { + return false; + } } - result = new StringScanResult(value, Encoding); + result = new StringScanResult(Value, Encoding); return true; } - public bool Compare(byte[] data, int index, ScanResult previous, out ScanResult result) + public unsafe bool Compare(byte* data, ScanResult previous, out ScanResult result) { #if DEBUG Debug.Assert(previous is StringScanResult); #endif - return Compare(data, index, out result); + return Compare(data, out result); } } } diff --git a/ReClass.NET/MemoryScanner/PatternScanner.cs b/ReClass.NET/MemoryScanner/PatternScanner.cs index 33adb8dd..619f8b6b 100644 --- a/ReClass.NET/MemoryScanner/PatternScanner.cs +++ b/ReClass.NET/MemoryScanner/PatternScanner.cs @@ -79,6 +79,8 @@ private static int FindPattern(BytePattern pattern, byte[] data) var limit = data.Length - pattern.Length; for (var i = 0; i < limit; ++i) { + // TODO: Use System.Span after it is available + // if (pattern.Equals(new Span(data, i, pattern.Length))) if (pattern.Equals(data, i)) { return i; diff --git a/ReClass.NET/MemoryScanner/ScanResultBlock.cs b/ReClass.NET/MemoryScanner/ScanResultBlock.cs index 14aad1ac..ab657c15 100644 --- a/ReClass.NET/MemoryScanner/ScanResultBlock.cs +++ b/ReClass.NET/MemoryScanner/ScanResultBlock.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Diagnostics.Contracts; using ReClassNET.Extensions; -using ReClassNET.Util; namespace ReClassNET.MemoryScanner { diff --git a/ReClass.NET/MemoryScanner/ScanResultStore.cs b/ReClass.NET/MemoryScanner/ScanResultStore.cs index 70a03d04..08417ab5 100644 --- a/ReClass.NET/MemoryScanner/ScanResultStore.cs +++ b/ReClass.NET/MemoryScanner/ScanResultStore.cs @@ -4,7 +4,6 @@ using System.IO; using System.Text; using ReClassNET.Extensions; -using ReClassNET.Util; namespace ReClassNET.MemoryScanner { diff --git a/ReClass.NET/MemoryScanner/ScannerWorker.cs b/ReClass.NET/MemoryScanner/ScannerWorker.cs index b83dc714..21b642ee 100644 --- a/ReClass.NET/MemoryScanner/ScannerWorker.cs +++ b/ReClass.NET/MemoryScanner/ScannerWorker.cs @@ -35,18 +35,24 @@ public IList Search(byte[] data, int count, CancellationToken ct) var endIndex = count - comparer.ValueSize; - for (var i = 0; i < endIndex; i += settings.FastScanAlignment) + unsafe { - if (ct.IsCancellationRequested) + fixed (byte* ptr = &data[0]) { - break; - } + for (var i = 0; i < endIndex; i += settings.FastScanAlignment) + { + if (ct.IsCancellationRequested) + { + break; + } - if (comparer.Compare(data, i, out var result)) - { - result.Address = (IntPtr)i; + if (comparer.Compare(ptr + i, out var result)) + { + result.Address = (IntPtr)i; - results.Add(result); + results.Add(result); + } + } } } @@ -71,21 +77,27 @@ public IList Search(byte[] data, int count, IEnumerable var endIndex = count - comparer.ValueSize; - foreach (var previousResult in previousResults) + unsafe { - if (ct.IsCancellationRequested) + fixed (byte* ptr = &data[0]) { - break; - } - - var offset = previousResult.Address.ToInt32(); - if (offset <= endIndex) - { - if (comparer.Compare(data, offset, previousResult, out var result)) + foreach (var previousResult in previousResults) { - result.Address = previousResult.Address; - - results.Add(result); + if (ct.IsCancellationRequested) + { + break; + } + + var offset = previousResult.Address.ToInt32(); + if (offset <= endIndex) + { + if (comparer.Compare(ptr + offset, previousResult, out var result)) + { + result.Address = previousResult.Address; + + results.Add(result); + } + } } } } diff --git a/ReClass.NET/ReClass.NET.csproj b/ReClass.NET/ReClass.NET.csproj index c8241085..96d8765c 100644 --- a/ReClass.NET/ReClass.NET.csproj +++ b/ReClass.NET/ReClass.NET.csproj @@ -26,7 +26,7 @@ TRACE;DEBUG;RECLASSNET32 prompt 4 - false + true False False True @@ -80,6 +80,7 @@ TRACE;RECLASSNET32;RELEASE prompt 4 + true x64 @@ -91,7 +92,7 @@ TRACE;DEBUG;RECLASSNET64 prompt 4 - false + true x64 @@ -102,6 +103,7 @@ TRACE;RECLASSNET64;RELEASE prompt 4 + true Resources\Icon\ReClassNet.ico