diff --git a/HexDump.Benchmark/FormatBenchmark.cs b/HexDump.Benchmark/FormatBenchmark.cs
new file mode 100644
index 0000000..deb940e
--- /dev/null
+++ b/HexDump.Benchmark/FormatBenchmark.cs
@@ -0,0 +1,72 @@
+
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Jobs;
+
+namespace HexDump.Benchmark
+{
+ // [ClrJob, CoreJob, MonoJob]
+ //[SimpleJob(RuntimeMoniker.Net472, baseline: true)]
+ //[SimpleJob(RuntimeMoniker.NetCoreApp30)]
+ [SimpleJob(RuntimeMoniker.NetCoreApp31)]
+ //[SimpleJob(RuntimeMoniker.CoreRt30)]
+ //[SimpleJob(RuntimeMoniker.Mono)]
+ [RPlotExporter]
+ [MemoryDiagnoser]
+ [ShortRunJob]
+ public class FormatBenchmark
+ {
+ private string _dump;
+
+ [Params(10, 100, 1000)]
+ public int _len;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ _dump = HexDump.Format(new byte[_len]);
+ }
+
+ [Benchmark]
+ public void ParseSimd()
+ {
+ HexDump.ParseSimd(_dump);
+ }
+
+ [Benchmark]
+ public void ParseLookup1()
+ {
+ HexDump.ParseLookup1(_dump);
+ }
+
+ [Benchmark]
+ public void ParseLookup2()
+ {
+ HexDump.ParseLookup2(_dump);
+ }
+
+ [Benchmark]
+ public void ParseStasteMachine()
+ {
+ HexDump.ParseStasteMachine(_dump);
+ }
+
+ [Benchmark]
+ public void ParseConvert()
+ {
+ HexDump.ParseConvert(_dump);
+ }
+
+ [Benchmark]
+ public void ParseDic()
+ {
+ HexDump.ParseDic(_dump);
+ }
+/** too slow to continue measures
+ [Benchmark]
+ public void ParseRegex()
+ {
+ HexDump.ParseRegex(_dump);
+ }
+**/
+ }
+}
\ No newline at end of file
diff --git a/HexDump.Benchmark/HexDump.Benchmark.csproj b/HexDump.Benchmark/HexDump.Benchmark.csproj
new file mode 100644
index 0000000..5d43650
--- /dev/null
+++ b/HexDump.Benchmark/HexDump.Benchmark.csproj
@@ -0,0 +1,20 @@
+
+
+
+
+ false
+
+ Exe
+
+ netcoreapp3.1
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HexDump.Benchmark/Program.cs b/HexDump.Benchmark/Program.cs
new file mode 100644
index 0000000..f80a49b
--- /dev/null
+++ b/HexDump.Benchmark/Program.cs
@@ -0,0 +1,12 @@
+using BenchmarkDotNet.Running;
+
+namespace HexDump.Benchmark
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ var summary = BenchmarkRunner.Run();
+ }
+ }
+}
\ No newline at end of file
diff --git a/HexDump.Tests/AnalyseTests.cs b/HexDump.Tests/AnalyseTests.cs
new file mode 100644
index 0000000..0fbd36b
--- /dev/null
+++ b/HexDump.Tests/AnalyseTests.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Linq;
+using Xunit;
+
+namespace HexDump.Tests
+{
+ public class AnalyseTests
+ {
+
+
+ [Fact]
+ public void When_Ascii_In_Ascii_Dont_Match()
+ {
+ var data = @"
+0000 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+0000 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+0000 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(8, config.Offset);
+ Assert.Equal(48, config.Hex);
+ Assert.Equal(21, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+ [Fact]
+ public void When_NoOffset_NoAscii()
+ {
+ var data = @"
+9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A
+9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(0, config.Offset);
+ Assert.Equal(48, config.Hex);
+ Assert.Equal(0, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+
+ [Fact]
+ public void When_NoOffset_NoAscii_OneLine()
+ {
+ var data = @"
+9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(0, config.Offset);
+ Assert.Equal(48, config.Hex);
+ Assert.Equal(0, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+ [Fact]
+ public void When_NoOffset_NoAscii_23_OneLine()
+ {
+ var data = @"
+9A 20 31 32 20 9A 9A 9A
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(0, config.Offset);
+ Assert.Equal(23, config.Hex);
+ Assert.Equal(0, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+
+
+ [Fact]
+ public void When_NoOffset_Ascii_In_Ascii_Dont_Match()
+ {
+ var data = @"
+9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(0, config.Offset);
+ Assert.Equal(48, config.Hex);
+ Assert.Equal(21, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+ [Fact]
+ public void When_NoOffset_Ascii_In_Ascii_OneLine_Match()
+ {
+ var data = @"
+9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(0, config.Offset);
+ Assert.Equal(48, config.Hex);
+ Assert.Equal(21, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+ [Fact]
+ public void When_NoOffset_Ascii_2_In_Ascii_OneLine_Match()
+ {
+ var data = @"
+9A
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(0, config.Offset);
+ Assert.Equal(2, config.Hex);
+ Assert.Equal(0, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+ [Fact]
+ public void When_NoOffset_Ascii_4_In_Ascii_OneLine_Match()
+ {
+ var data = @"
+9A 9A
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(0, config.Offset);
+ Assert.Equal(5, config.Hex);
+ Assert.Equal(0, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+
+ [Fact]
+ public void When_56a_Columns1_Width8_Ascii0_Offset1_Then_ok()
+ {
+
+ var data = @"
+0000 61 61 61 61 61 61 61 61
+0008 61 61 61 61 61 61 61 61
+0010 61 61 61 61 61 61 61 61
+0018 61 61 61 61 61 61 61 61
+0020 61 61 61 61 61 61 61 61
+0028 61 61 61 61 61 61 61 61
+0030 61 61 61 61 61 61 61 61
+".Trim();
+
+ var config = HexDump.Analyse(data.AsSpan());
+
+ Assert.Equal(8, config.Offset);
+ Assert.Equal(23, config.Hex);
+ Assert.Equal(0, config.Ascii);
+ Assert.Equal(1, config.NewLine);
+ }
+
+
+ [Fact]
+ public void When_56a_Columns1_Width8_Ascii1_Offset1_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 3;
+ int width = 4;
+ bool offset = true;
+ bool ascii = true;
+ var expected = @"
+0000 61 61 61 61 61 61 61 61 61 61 61 61 aaaa aaaa aaaa
+000C 61 61 61 61 61 61 61 61 61 61 61 61 aaaa aaaa aaaa
+0018 61 61 61 61 61 61 61 61 61 61 61 61 aaaa aaaa aaaa
+0024 61 61 61 61 61 61 61 61 61 61 61 61 aaaa aaaa aaaa
+0030 61 61 61 61 61 61 61 61 aaaa aaaa ".TrimStart();
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ Assert.Equal(expected, result);
+
+ var config = HexDump.Analyse(result.AsSpan());
+ Assert.Equal(8, config.Offset);
+ Assert.Equal(37, config.Hex);
+ Assert.Equal(18, config.Ascii);
+ //Assert.Equal(1, config.NewLine);
+ }
+ }
+}
diff --git a/HexDump.Tests/FormatColumnsAsciiOffsetTests.cs b/HexDump.Tests/FormatColumnsAsciiOffsetTests.cs
new file mode 100644
index 0000000..64b1935
--- /dev/null
+++ b/HexDump.Tests/FormatColumnsAsciiOffsetTests.cs
@@ -0,0 +1,307 @@
+using System.Linq;
+using Xunit;
+
+namespace HexDump.Tests
+{
+ public class FormatColumnsAsciiOffsetTests
+ {
+
+
+ [Fact]
+ public void When_Encode_56a_Columns1_Width8_Ascii1_Offset1_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 1;
+ int width = 8;
+ bool offset = true;
+ bool ascii = true;
+
+ var expected = @"
+0000 61 61 61 61 61 61 61 61 aaaaaaaa
+0008 61 61 61 61 61 61 61 61 aaaaaaaa
+0010 61 61 61 61 61 61 61 61 aaaaaaaa
+0018 61 61 61 61 61 61 61 61 aaaaaaaa
+0020 61 61 61 61 61 61 61 61 aaaaaaaa
+0028 61 61 61 61 61 61 61 61 aaaaaaaa
+0030 61 61 61 61 61 61 61 61 aaaaaaaa
+".Trim();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_56a_Columns1_Width8_Ascii1_Offset0_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 1;
+ int width = 8;
+ bool offset = false;
+ bool ascii = true;
+
+ var expected = @"
+61 61 61 61 61 61 61 61 aaaaaaaa
+61 61 61 61 61 61 61 61 aaaaaaaa
+61 61 61 61 61 61 61 61 aaaaaaaa
+61 61 61 61 61 61 61 61 aaaaaaaa
+61 61 61 61 61 61 61 61 aaaaaaaa
+61 61 61 61 61 61 61 61 aaaaaaaa
+61 61 61 61 61 61 61 61 aaaaaaaa
+".Trim();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+ [Fact]
+ public void When_Encode_56a_Columns1_Width8_Ascii0_Offset1_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 1;
+ int width = 8;
+ bool offset = true;
+ bool ascii = false;
+
+ var expected = @"
+0000 61 61 61 61 61 61 61 61
+0008 61 61 61 61 61 61 61 61
+0010 61 61 61 61 61 61 61 61
+0018 61 61 61 61 61 61 61 61
+0020 61 61 61 61 61 61 61 61
+0028 61 61 61 61 61 61 61 61
+0030 61 61 61 61 61 61 61 61
+".Trim();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_56a_Columns1_Width8_Ascii0_Offset0_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 1;
+ int width = 8;
+ bool offset = false;
+ bool ascii = false;
+
+ var expected = @"
+61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61
+".Trim();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+ [Fact]
+ public void When_Encode_56a_Columns2_Width8_Ascii1_Offset1_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 2;
+ int width = 8;
+ bool offset = true;
+ bool ascii = true;
+
+ var expected = @"
+0000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa
+0010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa
+0020 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa
+0030 61 61 61 61 61 61 61 61 aaaaaaaa ".TrimStart();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_56a_Columns2_Width8_Ascii1_Offset0_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 2;
+ int width = 8;
+ bool offset = false;
+ bool ascii = true;
+
+ var expected = @"
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa
+61 61 61 61 61 61 61 61 aaaaaaaa ".TrimStart();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+ [Fact]
+ public void When_Encode_56a_Columns2_Width8_Ascii0_Offset1_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 2;
+ int width = 8;
+ bool offset = true;
+ bool ascii = false;
+
+ var expected = @"
+0000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+0010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+0020 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+0030 61 61 61 61 61 61 61 61 ".TrimStart();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_56a_Columns2_Width8_Ascii0_Offset0_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 2;
+ int width = 8;
+ bool offset = false;
+ bool ascii = false;
+
+ var expected = @"
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 ".TrimStart();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_56a_Columns3_Width8_Ascii1_Offset1_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 3;
+ int width = 8;
+ bool offset = true;
+ bool ascii = true;
+
+ var expected = @"
+0000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa aaaaaaaa
+0018 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa aaaaaaaa
+0030 61 61 61 61 61 61 61 61 aaaaaaaa ".TrimStart();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_56a_Columns3_Width8_Ascii1_Offset0_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 3;
+ int width = 8;
+ bool offset = false;
+ bool ascii = true;
+
+ var expected = @"
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa aaaaaaaa
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa aaaaaaaa
+61 61 61 61 61 61 61 61 aaaaaaaa ".TrimStart();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_56a_Columns3_Width8_Ascii0_Offset1_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 3;
+ int width = 8;
+ bool offset = true;
+ bool ascii = false;
+
+ var expected = @"
+0000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+0018 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+0030 61 61 61 61 61 61 61 61 ".TrimStart();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_56a_Columns3_Width8_Ascii0_Offset0_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 56).ToArray();
+ int columns = 3;
+ int width = 8;
+ bool offset = false;
+ bool ascii = false;
+
+ var expected = @"
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+61 61 61 61 61 61 61 61 ".TrimStart();
+
+ var result = HexDump.Format(data, width, columns, offset, ascii);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed, width, columns, offset, ascii);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+ }
+
+}
diff --git a/HexDump.Tests/FormatSpecialCasesTests.cs b/HexDump.Tests/FormatSpecialCasesTests.cs
new file mode 100644
index 0000000..9d5e4cd
--- /dev/null
+++ b/HexDump.Tests/FormatSpecialCasesTests.cs
@@ -0,0 +1,104 @@
+using System.Linq;
+using Xunit;
+
+namespace HexDump.Tests
+{
+ public class FormatSpecialCasesTests
+ {
+
+
+ [Fact]
+ public void When_Ascii_In_Ascii_Dont_Match()
+ {
+ var data = @"
+0000 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+0010 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+0020 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+".Trim();
+
+ var parsed = HexDump.Parse(data);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(data, result2);
+ }
+
+ [Fact]
+ public void When_NoOffest_Work()
+ {
+ var data = @"
+9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+".Trim();
+
+ var parsed = HexDump.Parse(data);
+ var result2 = HexDump.Format(parsed, includeOffset: false);
+
+ Assert.Equal(data, result2);
+ }
+
+ [Fact]
+ public void When_NoAscii_Work()
+ {
+ var data = @"
+0000 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A
+".Trim();
+
+ var parsed = HexDump.Parse(data);
+ var result2 = HexDump.Format(parsed, includeAscii: false);
+
+ Assert.Equal(data, result2);
+ }
+
+
+ [Fact]
+ public void When_NoAscii_NoOffset_Work()
+ {
+ var data = @"
+9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A
+".Trim();
+
+ var parsed = HexDump.Parse(data);
+ var result2 = HexDump.Format(parsed, includeOffset: false, includeAscii: false);
+
+ Assert.Equal(data, result2);
+ }
+
+ [Fact]
+ public void When_OneByte_NoAscii_NoOffset_Work()
+ {
+ var data = @"
+9A
+".Trim();
+
+ var parsed = HexDump.Parse(data);
+ var result2 = HexDump.Format(parsed,
+ includeOffset: false,
+ includeAscii: false,
+ columnWidth: 1,
+ columnCount: 1
+ );
+
+ Assert.Equal(data, result2);
+ }
+
+
+ [Fact]
+ public void When_TwoBytes_NoAscii_NoOffset_Work()
+ {
+ var data = @"
+9A
+9A
+".Trim();
+
+ var parsed = HexDump.Parse(data);
+ var result2 = HexDump.Format(parsed,
+ includeOffset: false,
+ includeAscii: false,
+ columnWidth: 1,
+ columnCount: 1
+ );
+
+ Assert.Equal(data, result2);
+ }
+
+ }
+}
diff --git a/HexDump.Tests/FormatTests.cs b/HexDump.Tests/FormatTests.cs
new file mode 100644
index 0000000..1d6f486
--- /dev/null
+++ b/HexDump.Tests/FormatTests.cs
@@ -0,0 +1,240 @@
+using System.Linq;
+using Xunit;
+
+namespace HexDump.Tests
+{
+ public class FormatTests
+ {
+
+ [Fact]
+ public void When_Encode_16_Then_ok()
+ {
+ var data = new byte[16];
+ var expected = @"
+0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+".Trim();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void When_Encode_32_Then_ok()
+ {
+ var data = new byte[32];
+ var expected = @"
+0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+".Trim();;
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+
+ [Fact]
+ public void When_Encode_48_Then_ok()
+ {
+ var data = new byte[48];
+ var expected = @"
+0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+".Trim();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+
+ [Fact]
+ public void When_Encode_256_Then_ok()
+ {
+ var data = new byte[256];
+ var expected = @"
+0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+00F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+".Trim();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+
+ [Fact]
+ public void When_Encode_8_Then_ok()
+ {
+ var data = new byte[8];
+ var expected = @"
+0000 00 00 00 00 00 00 00 00 ........ ".TrimStart();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void When_Encode_0_Then_ok()
+ {
+ var data = new byte[0];
+ var expected = @"";
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+
+ [Fact]
+ public void When_Encode_24_Then_ok()
+ {
+ var data = new byte[24];
+ var expected = @"
+0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0010 00 00 00 00 00 00 00 00 ........ ".TrimStart();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void When_Encode_40_Then_ok()
+ {
+ var data = new byte[40];
+ var expected = @"
+0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
+0020 00 00 00 00 00 00 00 00 ........ ".TrimStart();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void When_Encode_40_one_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 1, 40).ToArray();
+
+ var expected = @"
+0000 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ........ ........
+0010 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 ........ ........
+0020 01 01 01 01 01 01 01 01 ........ ".TrimStart();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void When_Encode_100_ff_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 0xff, 100).ToArray();
+
+ var expected = @"
+0000 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿ
+0010 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿ
+0020 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿ
+0030 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿ
+0040 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿ
+0050 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ÿÿÿÿÿÿÿÿ ÿÿÿÿÿÿÿÿ
+0060 FF FF FF FF ÿÿÿÿ ".TrimStart();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+
+ [Fact]
+ public void When_Encode_128_9a_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 0x9a, 128).ToArray();
+
+ var expected = @"
+0000 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+0010 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+0020 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+0030 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+0040 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+0050 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+0060 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+0070 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A ........ ........
+".Trim();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result);
+ Assert.Equal(expected, result2);
+ }
+
+ [Fact]
+ public void When_Encode_40_61_Then_ok()
+ {
+ var data = Enumerable.Repeat((byte) 'a', 40).ToArray();
+
+ var expected = @"
+0000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa
+0010 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 aaaaaaaa aaaaaaaa
+0020 61 61 61 61 61 61 61 61 aaaaaaaa ".TrimStart();
+
+ var result = HexDump.Format(data);
+ var parsed = HexDump.Parse(result);
+ var result2 = HexDump.Format(parsed);
+
+ Assert.Equal(expected, result2);
+ Assert.Equal(expected, result);
+ }
+ }
+}
diff --git a/HexDump.Tests/HexDump.Tests.csproj b/HexDump.Tests/HexDump.Tests.csproj
index 75588cd..30367d6 100644
--- a/HexDump.Tests/HexDump.Tests.csproj
+++ b/HexDump.Tests/HexDump.Tests.csproj
@@ -1,7 +1,7 @@
- netcoreapp3.1;net45
+ netcoreapp3.1;net451
false
diff --git a/HexDump.sln b/HexDump.sln
index a68ca9d..54faceb 100644
--- a/HexDump.sln
+++ b/HexDump.sln
@@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexDump", "HexDump\HexDump.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexDump.Tests", "HexDump.Tests\HexDump.Tests.csproj", "{8F8380EE-289F-4AE6-A44B-720269DFA071}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexDump.Benchmark", "HexDump.Benchmark\HexDump.Benchmark.csproj", "{DF88229C-C00A-4EC0-8C43-F6731F10E75A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +23,10 @@ Global
{8F8380EE-289F-4AE6-A44B-720269DFA071}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8F8380EE-289F-4AE6-A44B-720269DFA071}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8F8380EE-289F-4AE6-A44B-720269DFA071}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DF88229C-C00A-4EC0-8C43-F6731F10E75A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DF88229C-C00A-4EC0-8C43-F6731F10E75A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DF88229C-C00A-4EC0-8C43-F6731F10E75A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DF88229C-C00A-4EC0-8C43-F6731F10E75A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/HexDump/HexDump.cs b/HexDump/HexDump.cs
index c2fc092..0f96efc 100644
--- a/HexDump/HexDump.cs
+++ b/HexDump/HexDump.cs
@@ -6,7 +6,7 @@
namespace HexDump
{
- public static class HexDump
+ public static partial class HexDump
{
[Pure]
public static string Format(byte[] bytes, int columnWidth = 8, int columnCount = 2, bool includeOffset = true, bool includeAscii = true)
diff --git a/HexDump/HexDump.csproj b/HexDump/HexDump.csproj
index f0890bb..f4f3c61 100644
--- a/HexDump/HexDump.csproj
+++ b/HexDump/HexDump.csproj
@@ -1,7 +1,7 @@
- netstandard2.0;net45
+ netstandard2.1;net45
true
portable
8
@@ -22,4 +22,10 @@
snupkg
+
+
+
+
+
+
diff --git a/HexDump/HexDumpParse.cs b/HexDump/HexDumpParse.cs
new file mode 100644
index 0000000..1c062ff
--- /dev/null
+++ b/HexDump/HexDumpParse.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Drew Noakes. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HexDump
+{
+ public static partial class HexDump
+ {
+
+ public static byte[] Parse(string dump)
+ {
+ return ParseStasteMachine(dump);
+ }
+
+ }
+}
diff --git a/HexDump/HexDumpParseConvert.cs b/HexDump/HexDumpParseConvert.cs
new file mode 100644
index 0000000..3266e06
--- /dev/null
+++ b/HexDump/HexDumpParseConvert.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Drew Noakes. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+
+namespace HexDump
+{
+ public static partial class HexDump
+ {
+ ///
+ /// Parse HexDump into a byte array
+ ///
+ ///
+ ///
+ public static byte[] ParseConvert(string dump)
+ {
+
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+ var result = new List();
+ var span = dump.AsSpan();
+ for (int i = 0; i < span.Length - 3; i++)
+ {
+
+ if (span[i] == ' ' && span[i+3] == ' '
+ && ((span[i+1] >= '0' && span[i+1] <= '9')
+ || (span[i+1] >= 'a' && span[i+1] <= 'f')
+ || (span[i+1] >= 'A' && span[i+1] <= 'F')
+ || (span[i+2] >= '0' && span[i+2] <= '9')
+ || (span[i+2] >= 'a' && span[i+2] <= 'f')
+ || (span[i+2] >= 'A' && span[i+2] <= 'F')
+ )
+ )
+ {
+ var s = span.Slice(i + 1, 2).ToString();
+ byte b = Convert.ToByte(s, 16);
+ result.Add(b);
+ }
+ }
+
+ return result.ToArray();
+ }
+
+ }
+}
diff --git a/HexDump/HexDumpParseDic.cs b/HexDump/HexDumpParseDic.cs
new file mode 100644
index 0000000..082f454
--- /dev/null
+++ b/HexDump/HexDumpParseDic.cs
@@ -0,0 +1,64 @@
+// Copyright (c) Drew Noakes. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HexDump
+{
+ public static partial class HexDump
+ {
+ static readonly Dictionary _dic =new Dictionary();
+
+ static HexDump()
+ {
+ var keys = "0123456789ABCEDF";
+ for (int i = 0; i < keys.Length; i++)
+ {
+ _dic[keys[i]] = i;
+ if (i > 10)
+ {
+ _dic[(char)(keys[i]+0x20)] = i;
+ }
+ }
+
+ }
+ ///
+ /// Parse HexDump into a byte array
+ ///
+ ///
+ ///
+ public static byte[] ParseDic(string dump)
+ {
+
+
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+ var result = new List();
+ var span = dump.AsSpan();
+ for (int i = 0; i < span.Length - 3; i++)
+ {
+
+ if (span[i] == ' ' && span[i+3] == ' '
+ && ((span[i+1] >= '0' && span[i+1] <= '9')
+ || (span[i+1] >= 'a' && span[i+1] <= 'f')
+ || (span[i+1] >= 'A' && span[i+1] <= 'F')
+ || (span[i+2] >= '0' && span[i+2] <= '9')
+ || (span[i+2] >= 'a' && span[i+2] <= 'f')
+ || (span[i+2] >= 'A' && span[i+2] <= 'F')
+ )
+ )
+ {
+
+ int dec = (_dic[span[i + 1]] * 16 + _dic[span[i + 2]]);
+ result.Add((byte)dec);
+ }
+ }
+
+ return result.ToArray();
+ }
+
+ }
+}
diff --git a/HexDump/HexDumpParseLookup1.cs b/HexDump/HexDumpParseLookup1.cs
new file mode 100644
index 0000000..79a6ae8
--- /dev/null
+++ b/HexDump/HexDumpParseLookup1.cs
@@ -0,0 +1,67 @@
+// Copyright (c) Drew Noakes. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HexDump
+{
+ public static partial class HexDump
+ {
+ private static readonly byte[] _lookup =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+
+ ///
+ /// Parse HexDump into a byte array
+ ///
+ ///
+ ///
+ public static byte[] ParseLookup1(string dump)
+ {
+
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+ var result = new List();
+ var span = dump.AsSpan();
+ for (int i = 0; i < span.Length - 3; i++)
+ {
+
+ if ( span[i] == ' '
+ && span[i+3] == ' '
+ && _lookup[span[i + 1]] != 0xff
+ && _lookup[span[i + 2]] != 0xff
+ )
+ {
+ int dec = (
+ _lookup[span[i + 1]] * 16
+ + _lookup[span[i + 2]]
+ );
+
+ result.Add((byte)dec);
+ }
+ }
+
+ return result.ToArray();
+ }
+
+ }
+}
diff --git a/HexDump/HexDumpParseLookup2.cs b/HexDump/HexDumpParseLookup2.cs
new file mode 100644
index 0000000..fba15d1
--- /dev/null
+++ b/HexDump/HexDumpParseLookup2.cs
@@ -0,0 +1,164 @@
+// Copyright (c) Drew Noakes. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HexDump
+{
+ public static partial class HexDump
+ {
+
+ private static readonly byte[] _lookup1 =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+
+ private static readonly byte[] _lookup2 =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+
+
+ private static readonly byte[] _sep =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ ///
+ /// Parse HexDump into a byte array
+ ///
+ ///
+ ///
+ public static byte[] ParseLookup2(string dump)
+ {
+
+ //0000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //0000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //0000 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ... ........
+
+ var result = new List();
+ var span = dump.AsSpan();
+ var len = span.Length;
+ bool ascii = false;
+ for (int i = 0; i < len - 3; i++)
+ {
+ if (
+ i == 0
+ && _sep[span[i+2]] == 0xFF
+ && _lookup1[span[i + 1]] != 0xff
+ && _lookup2[span[i + 2]] != 0xff
+ )
+ {
+ byte dec = (byte)(
+ _lookup1[span[i + 0]]
+ + _lookup2[span[i + 1]]
+ );
+
+ result.Add(dec);
+ }
+
+
+ // First char without offset (i==0)
+ if (
+ i == 0
+ && _sep[span[i+2]] == 0xFF
+ && _lookup1[span[i + 0]] != 0xff
+ && _lookup2[span[i + 1]] != 0xff
+ )
+ {
+ byte dec = (byte)(
+ _lookup1[span[i + 0]]
+ + _lookup2[span[i + 1]]
+ );
+
+ result.Add(dec);
+ }
+
+
+ // last char without ascii (i + 3 ==length)
+ else if (
+ _sep[span[i+1]] == 0xFF
+ && i + 4 == len
+ && _lookup1[span[i + 2]] != 0xff
+ && _lookup2[span[i + 3]] != 0xff
+ )
+ {
+ byte dec = (byte)(
+ _lookup1[span[i + 2]]
+ + _lookup2[span[i + 3]]
+ );
+
+ result.Add(dec);
+ }
+
+
+ else if (
+ _sep[span[i]] == 0xFF
+ && _sep[span[i+3]] == 0xFF
+ && _lookup1[span[i + 1]] != 0xff
+ && _lookup2[span[i + 2]] != 0xff
+ )
+ {
+ byte dec = (byte)(
+ _lookup1[span[i + 1]]
+ + _lookup2[span[i + 2]]
+ );
+
+ result.Add(dec);
+ }
+
+
+ }
+
+ return result.ToArray();
+ }
+
+ }
+}
diff --git a/HexDump/HexDumpParseRegex.cs b/HexDump/HexDumpParseRegex.cs
new file mode 100644
index 0000000..4ec896e
--- /dev/null
+++ b/HexDump/HexDumpParseRegex.cs
@@ -0,0 +1,68 @@
+// Copyright (c) Drew Noakes. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace HexDump
+{
+ public static partial class HexDump
+ {
+ ///
+ /// Parse HexDump into a byte array
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static byte[] ParseRegex2(string dump, int columnWidth = 8, int columnCount = 2, bool includeOffset = true, bool includeAscii = true, bool compileRegex = true)
+ {
+
+ string rio = includeOffset ? "((?[0-9a-f]+)\\s+)" : "";
+ string ria = includeAscii ? "(?.+)" : "";
+
+ var options = RegexOptions.IgnoreCase;
+ options = compileRegex
+ ? options | RegexOptions.Compiled
+ : options;
+
+ int hexaWidth = (columnWidth * 3 * columnCount) + columnCount - 1 - 1;
+ var _re = new Regex($"^{rio}(?[0-9a-f\\s]{{{hexaWidth}}}){ria}$",
+ options);
+
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+ string line;
+ var result = new List();
+ using (var sr = new StringReader(dump))
+ {
+ while ((line = sr.ReadLine()) != null)
+ {
+ var capture = _re.Match(line);
+ if (!capture.Success) continue;
+ var hexa = capture.Groups["hexa"]
+ .Value
+ .Replace(" ", "")
+ ;
+
+ var bytes = Enumerable.Range(0, hexa.Length)
+ .Where(x => x % 2 == 0)
+ .Select(x => Convert.ToByte(hexa.Substring(x, 2), 16))
+ ;
+
+ result.AddRange(bytes);
+ }
+ }
+
+ return result.ToArray();
+ }
+
+ }
+}
diff --git a/HexDump/HexDumpParseSimd.cs b/HexDump/HexDumpParseSimd.cs
new file mode 100644
index 0000000..714f0bc
--- /dev/null
+++ b/HexDump/HexDumpParseSimd.cs
@@ -0,0 +1,86 @@
+// Copyright (c) Drew Noakes. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Text;
+
+namespace HexDump
+{
+ public static partial class HexDump
+ {
+ private static readonly byte[] _lookupSimd = new byte[]
+ {
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ };
+
+ ///
+ /// Parse HexDump into a byte array
+ ///
+ ///
+ ///
+ public static byte[] ParseSimd(string dump)
+ {
+
+
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //00000000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+
+ var lb = new List();
+ var hb = new List();
+ var span = dump.AsSpan();
+ for (int i = 0; i < span.Length - 3; i++)
+ {
+
+ if (span[i] == ' ' && span[i+3] == ' '
+ && ((span[i+1] >= '0' && span[i+1] <= '9')
+ || (span[i+1] >= 'a' && span[i+1] <= 'f')
+ || (span[i+1] >= 'A' && span[i+1] <= 'F')
+ || (span[i+2] >= '0' && span[i+2] <= '9')
+ || (span[i+2] >= 'a' && span[i+2] <= 'f')
+ || (span[i+2] >= 'A' && span[i+2] <= 'F')
+ )
+ )
+ {
+ lb.Add(_lookupSimd[span[i + 1]]);
+ hb.Add(_lookupSimd[span[i + 2]]);
+ }
+ }
+
+ var ints = Simd(lb.ToArray(), hb.ToArray());
+ var result = new byte[ints.Length];
+ for (int i = 0; i < ints.Length; i++)
+ {
+ result[i] = (byte) ints[i];
+ }
+
+ return result;
+ }
+
+ public static int[] Simd(int[] lb, int[] hb)
+ {
+
+ var simdLength = Vector.Count;
+ var result = new int[lb.Length];
+ var hexs = new Vector(16);
+
+ var i = 0;
+ for (i = 0; i <= lb.Length - simdLength; i += simdLength) {
+
+ var vl = new Vector(lb, i);
+ var vh = new Vector(hb, i);
+ (vl * hexs + vh).CopyTo(result, i);
+ }
+
+ return result;
+ }
+
+ }
+}
diff --git a/HexDump/HexDumpParseStateMachine.cs b/HexDump/HexDumpParseStateMachine.cs
new file mode 100644
index 0000000..63195a7
--- /dev/null
+++ b/HexDump/HexDumpParseStateMachine.cs
@@ -0,0 +1,383 @@
+// Copyright (c) Drew Noakes. All Rights Reserved. Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace HexDump
+{
+ public static partial class HexDump
+ {
+
+ private static readonly byte[] _smlookup1 =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+
+ private static readonly byte[] _smlookup2 =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+
+
+ private static readonly byte[] _smsep =
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ public class Config
+ {
+ public int Offset;
+ public int Hex;
+ public int Ascii;
+ public int NewLine;
+ }
+
+ ///
+ /// Parse HexDump into a byte array
+ ///
+ ///
+ ///
+ public static byte[] ParseStasteMachine(string dump)
+ {
+
+ //0000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //0000 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
+ //0000 9A 20 31 32 20 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A 9A . 12 ...........
+
+ var result = new List();
+ var span = dump.AsSpan();
+ var len = span.Length;
+ var config = Analyse(span);
+
+ for (int i = 0; i < len;)
+ {
+
+ i += config.Offset;
+ for (int j = 0; j < config.Hex; j += 3)
+ {
+ var off = i + j;
+ if (off > len)
+ {
+ break;
+ }
+
+ if (_smlookup1[span[off + 0]] != 0xff
+ && _smlookup2[span[off + 1]] != 0xff)
+ {
+ byte dec = (byte) (
+ _smlookup1[span[off + 0]]
+ + _smlookup2[span[off + 1]]
+ );
+
+ result.Add(dec);
+ }
+
+ if (off + 3 < len
+ && span[off + 3] == ' ')
+ {
+ j++;
+ }
+ }
+
+ i += config.Hex;
+ i += config.Ascii;
+ i += config.NewLine;
+
+ }
+
+ return result.ToArray();
+ }
+
+ public static Config Analyse(in ReadOnlySpan span)
+ {
+ var p = new Process();
+ var len = span.Length;
+ var pm = new Config
+ {
+ NewLine = 1,
+ };
+
+ for (int i = 0; i < len; i++)
+ {
+ if (p.CurrentState == State.Started)
+ {
+ i += Started(span, i, len, pm, p);
+ }
+
+ else if (p.CurrentState == State.Offset)
+ {
+ i += Offset(span, i, len, pm, p);
+ }
+
+ else if (p.CurrentState == State.Hex)
+ {
+ i += Hex(span, i, len, pm, p);
+ }
+
+ else if (p.CurrentState == State.Ascii)
+ {
+ i += Ascii(span, i, len,pm, p);
+ }
+
+ else if (p.CurrentState == State.NewLine)
+ {
+ break;
+ }
+ else
+ {
+ break;
+ }
+
+ }
+
+ return pm;
+ }
+
+ private static int Ascii(ReadOnlySpan span, int i, int len, Config pm, Process p)
+ {
+ if (span[i] == '\r')
+ {
+ pm.NewLine = 2;
+ p.MoveNext(Command.NewLine);
+ return 0;
+ }
+
+ if (span[i] == '\n')
+ {
+ pm.NewLine = 1;
+ p.MoveNext(Command.NewLine);
+ }
+ return 0;
+ }
+
+ private static int Hex(ReadOnlySpan span, int i, int len, Config pm, Process p)
+ {
+ if (
+ i + 1 == len
+ )
+ {
+ pm.Ascii = i - pm.Offset - pm.Hex + 1;
+ p.MoveNext(Command.Ascii);
+ return 0;
+ }
+
+
+ if (
+ i + 1 < len
+ && (
+ span[i + 1] == '\n'
+ || span[i + 1] == '\r')
+ )
+ {
+ pm.Ascii = i - pm.Offset - pm.Hex + 1;
+ p.MoveNext(Command.Ascii);
+ return 0;
+ }
+
+ if (
+ span[i] == '\n'
+ || span[i] == '\r'
+ )
+ {
+ pm.Ascii = i - pm.Offset - pm.Hex;
+ p.MoveNext(Command.Ascii);
+ return 0;
+
+ }
+ return 0;
+
+ }
+
+ private static int Offset(ReadOnlySpan span, int i, int len, Config pm, Process p)
+ {
+ if (i + 3 >= len)
+ {
+ pm.Hex = len - pm.Offset;
+ p.MoveNext(Command.Hex);
+ return 0;
+ }
+
+ if (span[i] == ' '
+ && span[i + 1] == ' '
+ && span[i + 2] == ' '
+ && span[i + 3] == ' ')
+ {
+ pm.Hex = i - pm.Offset;
+ p.MoveNext(Command.Hex);
+ return 0;
+ }
+
+ if (span[i + 3] == '\n'
+ || span[i + 3] == '\r'
+ )
+ {
+ pm.Hex = i - pm.Offset + 3;
+ p.MoveNext(Command.Hex);
+ return 0;
+ }
+
+ return 0;
+
+ }
+
+ private static int Started(ReadOnlySpan span, int i, int len, Config pm, Process p)
+ {
+ if (len < 8)
+ {
+ pm.Offset = 0;
+ p.MoveNext(Command.Offset);
+ return 0;
+ }
+
+ int offset = 0;
+ if (_smlookup1[span[0]] != 0xff
+ && _smlookup2[span[0]] != 0xff
+ && _smlookup1[span[1]] != 0xff
+ && _smlookup2[span[1]] != 0xff
+ && _smlookup1[span[2]] != 0xff
+ && _smlookup2[span[2]] != 0xff
+ && _smlookup1[span[3]] != 0xff
+ && _smlookup2[span[3]] != 0xff
+ && span[4] == ' '
+ && span[5] == ' '
+ && span[6] == ' '
+ && span[7] == ' '
+ )
+ {
+ offset = 8;
+ }
+
+ pm.Offset = offset;
+ p.MoveNext(Command.Offset);
+ return offset;
+ }
+
+
+ public enum State : int
+ {
+ Started = 0,
+ Offset,
+ Hex,
+ Ascii,
+ NewLine,
+ Analysed
+ }
+
+ public enum Command
+ {
+ Offset,
+ Hex,
+ Ascii,
+ NewLine,
+ Analysed
+ }
+
+ public class Process
+ {
+ class StateTransition
+ {
+ readonly State Current;
+ readonly Command Command;
+
+ public StateTransition(State current, Command command)
+ {
+ Current = current;
+ Command = command;
+ }
+
+ public override int GetHashCode()
+ {
+ return 17 + 31 * Current.GetHashCode() + 31 * Command.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ StateTransition other = obj as StateTransition;
+ return other != null && this.Current == other.Current
+ && this.Command == other.Command;
+ }
+ }
+
+ Dictionary transitions;
+ public State CurrentState { get; private set; }
+
+ public Process()
+ {
+ CurrentState = State.Started;
+ transitions = new Dictionary
+ {
+ {new StateTransition(State.Started, Command.Offset), State.Offset},
+ {new StateTransition(State.Offset, Command.Hex), State.Hex},
+ {new StateTransition(State.Hex, Command.Ascii), State.Ascii},
+ {new StateTransition(State.Ascii, Command.NewLine), State.NewLine},
+ {new StateTransition(State.Hex, Command.NewLine), State.NewLine},
+ {new StateTransition(State.NewLine, Command.Analysed), State.Analysed},
+ {new StateTransition(State.Hex, Command.Analysed), State.Analysed},
+ };
+ }
+
+ public State GetNext(Command command)
+ {
+ StateTransition transition = new StateTransition(CurrentState, command);
+ State nextState;
+ if (!transitions.TryGetValue(transition, out nextState))
+ throw new Exception("Invalid transition: " + CurrentState + " -> " + command);
+ return nextState;
+ }
+
+ public State MoveNext(Command command)
+ {
+ CurrentState = GetNext(command);
+ return CurrentState;
+ }
+
+ }
+ }
+}