diff --git a/CHANGELIST.md b/CHANGELIST.md
index 6069d91c..0c1d18d3 100644
--- a/CHANGELIST.md
+++ b/CHANGELIST.md
@@ -24,6 +24,7 @@
- Use recommended Min/Max/TryParse
- Add tests around ProcessingTool
- Add BaseExecutionContext tests
+- Add currently unused Input type
### 3.2.4 (2024-11-24)
diff --git a/MPF.ExecutionContexts.Test/InputTests.cs b/MPF.ExecutionContexts.Test/InputTests.cs
new file mode 100644
index 00000000..6838ec1a
--- /dev/null
+++ b/MPF.ExecutionContexts.Test/InputTests.cs
@@ -0,0 +1,526 @@
+using Xunit;
+
+namespace MPF.ExecutionContexts.Test
+{
+ public class InputTests
+ {
+ #region ProcessAsFlag
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.Boolean, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.Int8, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.UInt8, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.Int16, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.UInt16, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.Int32, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.UInt32, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.Int64, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.UInt64, "flag", new string[] { "flag" }, 0, false)]
+ [InlineData(InputType.String, "flag", new string[] { "flag" }, 0, false)]
+ // Invalid parts
+ [InlineData(InputType.Flag, "flag", new string[0], 0, false)]
+ // Invalid index
+ [InlineData(InputType.Flag, "flag", new string[] { "flag" }, -1, false)]
+ [InlineData(InputType.Flag, "flag", new string[] { "flag" }, 1, false)]
+ // Invalid name
+ [InlineData(InputType.Flag, "flag", new string[] { "" }, 0, false)]
+ [InlineData(InputType.Flag, "flag", new string[] { "flag2" }, 0, false)]
+ // Valid
+ [InlineData(InputType.Flag, "flag", new string[] { "flag" }, 0, true)]
+ public void ProcessAsFlagTest(InputType type, string name, string[] parts, int index, bool expected)
+ {
+ Input input = new Input(type, name);
+ bool actual = input.ProcessAsFlag(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsBoolean
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.Boolean, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", false, new string[] { "flag" }, 0, true)]
+ // Valid name, invalid following
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", false, new string[] { "flag", "invalid" }, 0, true)]
+ // Valid name, valid following
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag", "true" }, 0, true)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag", "false" }, 0, false)]
+ public void ProcessAsBooleanTest(InputType type, string name, bool required, string[] parts, int index, bool? expected)
+ {
+ Input input = new Input(type, name, required);
+ bool? actual = input.ProcessAsBoolean(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsInt8
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.Int8, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.Int8, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", false, new string[] { "flag" }, 0, sbyte.MinValue)]
+ // Valid name, invalid following
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", false, new string[] { "flag", "invalid" }, 0, sbyte.MinValue)]
+ // Valid name, valid following
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag", "1" }, 0, (sbyte)1)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag", "-1" }, 0, (sbyte)-1)]
+ public void ProcessAsInt8Test(InputType type, string name, bool required, string[] parts, int index, sbyte? expected)
+ {
+ Input input = new Input(type, name, required);
+ sbyte? actual = input.ProcessAsInt8(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsUInt8
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.UInt8, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", false, new string[] { "flag" }, 0, byte.MinValue)]
+ // Valid name, invalid following
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", false, new string[] { "flag", "invalid" }, 0, byte.MinValue)]
+ // Valid name, valid following
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag", "1" }, 0, (byte)1)]
+ public void ProcessAsUInt8Test(InputType type, string name, bool required, string[] parts, int index, byte? expected)
+ {
+ Input input = new Input(type, name, required);
+ byte? actual = input.ProcessAsUInt8(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsInt16
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.Int16, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.Int16, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", false, new string[] { "flag" }, 0, short.MinValue)]
+ // Valid name, invalid following
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", false, new string[] { "flag", "invalid" }, 0, short.MinValue)]
+ // Valid name, valid following
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag", "1" }, 0, (short)1)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag", "-1" }, 0, (short)-1)]
+ public void ProcessAsInt16Test(InputType type, string name, bool required, string[] parts, int index, short? expected)
+ {
+ Input input = new Input(type, name, required);
+ short? actual = input.ProcessAsInt16(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsUInt16
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.UInt16, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", false, new string[] { "flag" }, 0, ushort.MinValue)]
+ // Valid name, invalid following
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", false, new string[] { "flag", "invalid" }, 0, ushort.MinValue)]
+ // Valid name, valid following
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag", "1" }, 0, (ushort)1)]
+ public void ProcessAsUInt16Test(InputType type, string name, bool required, string[] parts, int index, ushort? expected)
+ {
+ Input input = new Input(type, name, required);
+ ushort? actual = input.ProcessAsUInt16(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsInt32
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.Int32, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.Int32, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", false, new string[] { "flag" }, 0, int.MinValue)]
+ // Valid name, invalid following
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", false, new string[] { "flag", "invalid" }, 0, int.MinValue)]
+ // Valid name, valid following
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag", "1" }, 0, (int)1)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag", "-1" }, 0, (int)-1)]
+ public void ProcessAsInt32Test(InputType type, string name, bool required, string[] parts, int index, int? expected)
+ {
+ Input input = new Input(type, name, required);
+ int? actual = input.ProcessAsInt32(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsUInt32
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.UInt32, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", false, new string[] { "flag" }, 0, uint.MinValue)]
+ // Valid name, invalid following
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", false, new string[] { "flag", "invalid" }, 0, uint.MinValue)]
+ // Valid name, valid following
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag", "1" }, 0, (uint)1)]
+ public void ProcessAsUInt32Test(InputType type, string name, bool required, string[] parts, int index, uint? expected)
+ {
+ Input input = new Input(type, name, required);
+ uint? actual = input.ProcessAsUInt32(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsInt64
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.Int64, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.Int64, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", false, new string[] { "flag" }, 0, long.MinValue)]
+ // Valid name, invalid following
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", false, new string[] { "flag", "invalid" }, 0, long.MinValue)]
+ // Valid name, valid following
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag", "1" }, 0, (long)1)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag", "-1" }, 0, (long)-1)]
+ public void ProcessAsInt64Test(InputType type, string name, bool required, string[] parts, int index, long? expected)
+ {
+ Input input = new Input(type, name, required);
+ long? actual = input.ProcessAsInt64(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsUInt64
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.UInt64, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", false, new string[] { "flag" }, 0, ulong.MinValue)]
+ // Valid name, invalid following
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag", "invalid" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", false, new string[] { "flag", "invalid" }, 0, ulong.MinValue)]
+ // Valid name, valid following
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag", "1" }, 0, (ulong)1)]
+ public void ProcessAsUInt64Test(InputType type, string name, bool required, string[] parts, int index, ulong? expected)
+ {
+ Input input = new Input(type, name, required);
+ ulong? actual = input.ProcessAsUInt64(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region ProcessAsString
+
+ [Theory]
+ // Invalid type
+ [InlineData(InputType.None, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Flag, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Boolean, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt8, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt16, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt32, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.Int64, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.UInt64, "flag", true, new string[] { "flag" }, 0, null)]
+ // Invalid parts
+ [InlineData(InputType.String, "flag", true, new string[0], 0, null)]
+ // Invalid index
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, -1, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 1, null)]
+ // Invalid name
+ [InlineData(InputType.String, "flag", true, new string[] { "" }, 0, null)]
+ [InlineData(InputType.String, "flag", true, new string[] { "flag2" }, 0, null)]
+ // Valid name, no following
+ [InlineData(InputType.String, "flag", true, new string[] { "flag" }, 0, null)]
+ [InlineData(InputType.String, "flag", false, new string[] { "flag" }, 0, "")]
+ // Valid name, following
+ [InlineData(InputType.String, "flag", true, new string[] { "flag", "value" }, 0, "value")]
+ public void ProcessAsString(InputType type, string name, bool required, string[] parts, int index, string? expected)
+ {
+ Input input = new Input(type, name, required);
+ string? actual = input.ProcessAsString(parts, ref index);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+
+ #region DoesExist
+
+ [Fact]
+ public void DoesExist_Empty_False()
+ {
+ string[] parts = [];
+ int index = 0;
+ bool actual = Input.DoesExist(parts, index);
+ Assert.False(actual);
+ }
+
+ [Fact]
+ public void DoesExist_Negative_False()
+ {
+ string[] parts = ["item"];
+ int index = -1;
+ bool actual = Input.DoesExist(parts, index);
+ Assert.False(actual);
+ }
+
+ [Fact]
+ public void DoesExist_Greater_False()
+ {
+ string[] parts = ["item"];
+ int index = 1;
+ bool actual = Input.DoesExist(parts, index);
+ Assert.False(actual);
+ }
+
+ [Fact]
+ public void DoesExist_Valid_True()
+ {
+ string[] parts = ["item"];
+ int index = 0;
+ bool actual = Input.DoesExist(parts, index);
+ Assert.True(actual);
+ }
+
+ #endregion
+
+ #region ExtractFactorFromValue
+
+ [Theory]
+ [InlineData("1", "1", 1)]
+ [InlineData("1c", "1", 1)]
+ [InlineData("1w", "1", 2)]
+ [InlineData("1d", "1", 4)]
+ [InlineData("1q", "1", 8)]
+ [InlineData("1k", "1", 1024)]
+ [InlineData("1M", "1", 1024 * 1024)]
+ [InlineData("1G", "1", 1024 * 1024 * 1024)]
+ public void ExtractFactorFromValueTest(string value, string expected, long expectedFactor)
+ {
+ string actual = Input.ExtractFactorFromValue(value, out long factor);
+ Assert.Equal(expected, actual);
+ Assert.Equal(expectedFactor, factor);
+ }
+
+ #endregion
+
+ #region RemoveHexIdentifier
+
+ [Theory]
+ [InlineData("", "")]
+ [InlineData("0", "0")]
+ [InlineData("00", "00")]
+ [InlineData("0x", "0x")]
+ [InlineData("0X", "0X")]
+ [InlineData("A", "A")]
+ [InlineData("A0", "A0")]
+ [InlineData("Ax", "Ax")]
+ [InlineData("AX", "AX")]
+ [InlineData("012345", "012345")]
+ [InlineData("0x12345", "12345")]
+ [InlineData("0X12345", "12345")]
+ public void RemoveHexIdentifierTest(string value, string expected)
+ {
+ string actual = Input.RemoveHexIdentifier(value);
+ Assert.Equal(expected, actual);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/MPF.ExecutionContexts/Input.cs b/MPF.ExecutionContexts/Input.cs
new file mode 100644
index 00000000..818c67b6
--- /dev/null
+++ b/MPF.ExecutionContexts/Input.cs
@@ -0,0 +1,753 @@
+using System;
+using System.Globalization;
+
+namespace MPF.ExecutionContexts
+{
+ ///
+ /// Indicates the input type
+ ///
+ public enum InputType
+ {
+ None,
+ Flag,
+ Boolean,
+ Int8,
+ UInt8,
+ Int16,
+ UInt16,
+ Int32,
+ UInt32,
+ Int64,
+ UInt64,
+ String,
+ }
+
+ ///
+ /// Represents a single input for an execution context
+ ///
+ public class Input
+ {
+ #region Properties
+
+ ///
+ /// Input type for parsing
+ ///
+ public readonly InputType InputType;
+
+ ///
+ /// Primary name for the input
+ ///
+ public readonly string Name;
+
+ ///
+ /// Verbose name for the input
+ ///
+ private readonly string? _longName;
+
+ ///
+ /// Indicates if the value following is required or not
+ ///
+ private readonly bool _required;
+
+ #endregion
+
+ #region Constructors
+
+ /// Type of input for parsing
+ /// Flag name / value
+ public Input(InputType type, string name)
+ {
+ InputType = type;
+ Name = name;
+ _longName = null;
+ _required = true;
+ }
+
+ /// Type of input for parsing
+ /// Flag name / value
+ /// Indicates if a following value is required
+ public Input(InputType type, string name, bool required)
+ {
+ InputType = type;
+ Name = name;
+ _longName = null;
+ _required = required;
+ }
+
+ /// Type of input for parsing
+ /// Flag name / value
+ /// Verbose flag name / value
+ public Input(InputType type, string shortName, string longName)
+ {
+ InputType = type;
+ Name = shortName;
+ _longName = longName;
+ _required = true;
+ }
+
+ /// Type of input for parsing
+ /// Flag name / value
+ /// Verbose flag name / value
+ /// Indicates if a following value is required
+ public Input(InputType type, string shortName, string longName, bool required)
+ {
+ InputType = type;
+ Name = shortName;
+ _longName = longName;
+ _required = required;
+ }
+
+ #endregion
+
+ #region Processors
+
+ ///
+ /// Process the input as a flag
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// True if the flag was set, false otherwise
+ public bool ProcessAsFlag(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.Flag)
+ return false;
+
+ // Check the parts array
+ if (parts.Length == 0)
+ return false;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return false;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ return true;
+
+ return false;
+ }
+
+ ///
+ /// Process the input as a boolean
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// Boolean value if set, null otherwise
+ public bool? ProcessAsBoolean(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.Boolean)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : true;
+
+ // If the next value is valid
+ if (!bool.TryParse(parts[index + 1], out bool value))
+ return _required ? null : true;
+
+ index++;
+ return value;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as an Int8
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// Int8 value if set, minimum value if not required and missing, null otherwise
+ public sbyte? ProcessAsInt8(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.Int8)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : sbyte.MinValue;
+
+ // If the next value is valid
+ if (sbyte.TryParse(parts[index + 1], out sbyte value))
+ {
+ index++;
+ return value;
+ }
+
+ // Try to process as a formatted string
+ string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
+ if (sbyte.TryParse(baseVal, out value))
+ {
+ index++;
+ return (sbyte)(value * factor);
+ }
+
+ // Try to process as a hex string
+ string hexValue = RemoveHexIdentifier(baseVal);
+ if (sbyte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
+ {
+ index++;
+ return (sbyte)(value * factor);
+ }
+
+ // Return value based on required flag
+ return _required ? null : sbyte.MinValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as a UInt8
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// UInt8 value if set, minimum value if not required and missing, null otherwise
+ public byte? ProcessAsUInt8(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.UInt8)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : byte.MinValue;
+
+ // If the next value is valid
+ if (byte.TryParse(parts[index + 1], out byte value))
+ {
+ index++;
+ return value;
+ }
+
+ // Try to process as a formatted string
+ string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
+ if (byte.TryParse(baseVal, out value))
+ {
+ index++;
+ return (byte)(value * factor);
+ }
+
+ // Try to process as a hex string
+ string hexValue = RemoveHexIdentifier(baseVal);
+ if (byte.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
+ {
+ index++;
+ return (byte)(value * factor);
+ }
+
+ // Return value based on required flag
+ return _required ? null : byte.MinValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as an Int16
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// Int16 value if set, minimum value if not required and missing, null otherwise
+ public short? ProcessAsInt16(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.Int16)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : short.MinValue;
+
+ // If the next value is valid
+ if (short.TryParse(parts[index + 1], out short value))
+ {
+ index++;
+ return value;
+ }
+
+ // Try to process as a formatted string
+ string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
+ if (short.TryParse(baseVal, out value))
+ {
+ index++;
+ return (short)(value * factor);
+ }
+
+ // Try to process as a hex string
+ string hexValue = RemoveHexIdentifier(baseVal);
+ if (short.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
+ {
+ index++;
+ return (short)(value * factor);
+ }
+
+ // Return value based on required flag
+ return _required ? null : short.MinValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as a UInt16
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// UInt16 value if set, minimum value if not required and missing, null otherwise
+ public ushort? ProcessAsUInt16(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.UInt16)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : ushort.MinValue;
+
+ // If the next value is valid
+ if (ushort.TryParse(parts[index + 1], out ushort value))
+ {
+ index++;
+ return value;
+ }
+
+ // Try to process as a formatted string
+ string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
+ if (ushort.TryParse(baseVal, out value))
+ {
+ index++;
+ return (ushort)(value * factor);
+ }
+
+ // Try to process as a hex string
+ string hexValue = RemoveHexIdentifier(baseVal);
+ if (ushort.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
+ {
+ index++;
+ return (ushort)(value * factor);
+ }
+
+ // Return value based on required flag
+ return _required ? null : ushort.MinValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as an Int32
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// Int32 value if set, minimum value if not required and missing, null otherwise
+ public int? ProcessAsInt32(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.Int32)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : int.MinValue;
+
+ // If the next value is valid
+ if (int.TryParse(parts[index + 1], out int value))
+ {
+ index++;
+ return value;
+ }
+
+ // Try to process as a formatted string
+ string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
+ if (int.TryParse(baseVal, out value))
+ {
+ index++;
+ return (int)(value * factor);
+ }
+
+ // Try to process as a hex string
+ string hexValue = RemoveHexIdentifier(baseVal);
+ if (int.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
+ {
+ index++;
+ return (int)(value * factor);
+ }
+
+ // Return value based on required flag
+ return _required ? null : int.MinValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as a UInt32
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// UInt32 value if set, minimum value if not required and missing, null otherwise
+ public uint? ProcessAsUInt32(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.UInt32)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : uint.MinValue;
+
+ // If the next value is valid
+ if (uint.TryParse(parts[index + 1], out uint value))
+ {
+ index++;
+ return value;
+ }
+
+ // Try to process as a formatted string
+ string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
+ if (uint.TryParse(baseVal, out value))
+ {
+ index++;
+ return (uint)(value * factor);
+ }
+
+ // Try to process as a hex string
+ string hexValue = RemoveHexIdentifier(baseVal);
+ if (uint.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
+ {
+ index++;
+ return (uint)(value * factor);
+ }
+
+ // Return value based on required flag
+ return _required ? null : uint.MinValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as an Int64
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// Int64 value if set, minimum value if not required and missing, null otherwise
+ public long? ProcessAsInt64(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.Int64)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : long.MinValue;
+
+ // If the next value is valid
+ if (long.TryParse(parts[index + 1], out long value))
+ {
+ index++;
+ return value;
+ }
+
+ // Try to process as a formatted string
+ string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
+ if (long.TryParse(baseVal, out value))
+ {
+ index++;
+ return (long)(value * factor);
+ }
+
+ // Try to process as a hex string
+ string hexValue = RemoveHexIdentifier(baseVal);
+ if (long.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
+ {
+ index++;
+ return (long)(value * factor);
+ }
+
+ // Return value based on required flag
+ return _required ? null : long.MinValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as a UInt64
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// UInt64 value if set, minimum value if not required and missing, null otherwise
+ public ulong? ProcessAsUInt64(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.UInt64)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : ulong.MinValue;
+
+ // If the next value is valid
+ if (ulong.TryParse(parts[index + 1], out ulong value))
+ {
+ index++;
+ return value;
+ }
+
+ // Try to process as a formatted string
+ string baseVal = ExtractFactorFromValue(parts[index + 1], out long factor);
+ if (ulong.TryParse(baseVal, out value))
+ {
+ index++;
+ return (ulong)(value * (ulong)factor);
+ }
+
+ // Try to process as a hex string
+ string hexValue = RemoveHexIdentifier(baseVal);
+ if (ulong.TryParse(hexValue, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out value))
+ {
+ index++;
+ return (ulong)(value * (ulong)factor);
+ }
+
+ // Return value based on required flag
+ return _required ? null : ulong.MinValue;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Process the input as a UInt64
+ ///
+ /// Parts array to be referenced
+ /// Reference to the position in the parts
+ /// String value if set, empty value if not required and missing, null otherwise
+ public string? ProcessAsString(string[] parts, ref int index)
+ {
+ // Check the input type
+ if (InputType != InputType.String)
+ return null;
+
+ // Check the parts array
+ if (parts == null || parts.Length == 0)
+ return null;
+
+ // Check the index
+ if (index < 0 || index >= parts.Length)
+ return null;
+
+ // Check the name
+ if (parts[index] == Name || (_longName != null && parts[index] == _longName))
+ {
+ // Ensure the value exists
+ if (!DoesExist(parts, index + 1))
+ return _required ? null : string.Empty;
+
+ index++;
+ return parts[index];
+ }
+
+ return null;
+ }
+
+ #endregion
+
+ #region Helpers
+
+ ///
+ /// Returns whether or not the selected item exists
+ ///
+ /// Parts array to be referenced
+ /// Current index
+ /// True if the next item exists, false otherwise
+ internal static bool DoesExist(string[] parts, int index)
+ => index >= 0 && index < parts.Length;
+
+ ///
+ /// Get the trimmed value and multiplication factor from a value
+ ///
+ /// String value to treat as suffixed number
+ /// Trimmed value and multiplication factor
+ internal static string ExtractFactorFromValue(string value, out long factor)
+ {
+ value = value.Trim('"');
+ factor = 1;
+
+ // Characters
+ if (value.EndsWith("c", StringComparison.Ordinal))
+ {
+ factor = 1;
+ value = value.TrimEnd('c');
+ }
+
+ // Words
+ else if (value.EndsWith("w", StringComparison.Ordinal))
+ {
+ factor = 2;
+ value = value.TrimEnd('w');
+ }
+
+ // Double Words
+ else if (value.EndsWith("d", StringComparison.Ordinal))
+ {
+ factor = 4;
+ value = value.TrimEnd('d');
+ }
+
+ // Quad Words
+ else if (value.EndsWith("q", StringComparison.Ordinal))
+ {
+ factor = 8;
+ value = value.TrimEnd('q');
+ }
+
+ // Kilobytes
+ else if (value.EndsWith("k", StringComparison.Ordinal))
+ {
+ factor = 1024;
+ value = value.TrimEnd('k');
+ }
+
+ // Megabytes
+ else if (value.EndsWith("M", StringComparison.Ordinal))
+ {
+ factor = 1024 * 1024;
+ value = value.TrimEnd('M');
+ }
+
+ // Gigabytes
+ else if (value.EndsWith("G", StringComparison.Ordinal))
+ {
+ factor = 1024 * 1024 * 1024;
+ value = value.TrimEnd('G');
+ }
+
+ return value;
+ }
+
+ ///
+ /// Removes a leading 0x if it exists, case insensitive
+ ///
+ /// String with removed leading 0x
+ ///
+ internal static string RemoveHexIdentifier(string value)
+ {
+ if (value.Length <= 2)
+ return value;
+ if (value[0] != '0')
+ return value;
+ if (value[1] != 'x' && value[1] != 'X')
+ return value;
+
+ return value.Substring(2);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file