diff --git a/PKHeX.Core/Saves/SAV1.cs b/PKHeX.Core/Saves/SAV1.cs
index e12967e46..6c1c50e2d 100644
--- a/PKHeX.Core/Saves/SAV1.cs
+++ b/PKHeX.Core/Saves/SAV1.cs
@@ -267,8 +267,8 @@ namespace PKHeX.Core
public int PikaBeachScore
{
- get => BigEndian.BCDToInt32_LE(Data, Offsets.PikaBeachScore, 2);
- set => SetData(BigEndian.Int32ToBCD_LE(Math.Min(9999, value), 2), Offsets.PikaBeachScore);
+ get => BinaryCodedDecimal.ToInt32LE(Data, Offsets.PikaBeachScore, 2);
+ set => BinaryCodedDecimal.WriteBytesLE(Data.AsSpan(Offsets.PikaBeachScore, 2), Math.Min(9999, value));
}
public override string PlayTimeString => !PlayedMaximum ? base.PlayTimeString : $"{base.PlayTimeString} {Checksums.CRC16_CCITT(Data):X4}";
@@ -353,21 +353,21 @@ namespace PKHeX.Core
public override uint Money
{
- get => (uint)BigEndian.BCDToInt32(Data, Offsets.Money, 3);
+ get => (uint)BinaryCodedDecimal.ToInt32BE(Data, Offsets.Money, 3);
set
{
value = (uint)Math.Min(value, MaxMoney);
- BigEndian.Int32ToBCD((int)value, 3).CopyTo(Data, Offsets.Money);
+ BinaryCodedDecimal.WriteBytesBE(Data.AsSpan(Offsets.Money, 3), (int)value);
}
}
public uint Coin
{
- get => (uint)BigEndian.BCDToInt32(Data, Offsets.Coin, 2);
+ get => (uint)BinaryCodedDecimal.ToInt32BE(Data, Offsets.Coin, 2);
set
{
value = (ushort)Math.Min(value, MaxCoins);
- BigEndian.Int32ToBCD((int)value, 2).CopyTo(Data, Offsets.Coin);
+ BinaryCodedDecimal.WriteBytesBE(Data.AsSpan(Offsets.Coin, 2), (int)value);
}
}
diff --git a/PKHeX.Core/Util/BigEndian.cs b/PKHeX.Core/Util/BigEndian.cs
index 8cc557f60..a57e8f4f2 100644
--- a/PKHeX.Core/Util/BigEndian.cs
+++ b/PKHeX.Core/Util/BigEndian.cs
@@ -128,79 +128,5 @@ namespace PKHeX.Core
data[2 + i] = tmp1;
}
}
-
- ///
- /// Returns a 32-bit signed integer converted from bytes in a Binary Coded Decimal format byte array.
- ///
- /// Input byte array to read from.
- /// Offset to start reading at.
- /// Length of array to read.
- public static int BCDToInt32(byte[] input, int offset, int length)
- {
- int result = 0;
- for (int i = offset; i < offset + length; i++)
- {
- byte p = input[i];
- result *= 100;
- result += 10 * (p >> 4);
- result += p & 0xf;
- }
- return result;
- }
-
- ///
- /// Returns the specified 32-bit signed integer value as an array of Binary Coded Decimal format bytes.
- ///
- /// 32-bit signed integer to convert.
- /// Desired size of returned array.
- public static byte[] Int32ToBCD(int input, int size)
- {
- byte[] result = new byte[size];
- for (int i = 0; i < size; i++)
- {
- int p = input%100;
- input /= 100;
- result[size - i - 1] = (byte)(p/10 << 4 | p%10);
- }
- return result;
- }
-
- ///
- /// Returns a 16-bit signed integer converted from bytes in a Binary Coded Decimal format byte array.
- ///
- /// Little Endian instead of Big Endian
- /// Input byte array to read from.
- /// Offset to start reading at.
- /// Length of array to read.
- public static int BCDToInt32_LE(byte[] input, int offset, int length)
- {
- int result = 0;
- for (int i = offset + length - 1; i >= offset; i--)
- {
- byte p = input[i];
- result *= 100;
- result += 10 * (p >> 4);
- result += p & 0xf;
- }
- return result;
- }
-
- ///
- /// Returns the specified 32-bit signed integer value as an array of Binary Coded Decimal format bytes.
- ///
- /// Little Endian instead of Big Endian
- /// 32-bit signed integer to convert.
- /// Desired size of returned array.
- public static byte[] Int32ToBCD_LE(int input, int size)
- {
- byte[] result = new byte[size];
- for (int i = size - 1; i >= 0; i--)
- {
- int p = input % 100;
- input /= 100;
- result[size - i - 1] = (byte)(p / 10 << 4 | p % 10);
- }
- return result;
- }
}
}
diff --git a/PKHeX.Core/Util/BinaryCodedDecimal.cs b/PKHeX.Core/Util/BinaryCodedDecimal.cs
new file mode 100644
index 000000000..99a82e026
--- /dev/null
+++ b/PKHeX.Core/Util/BinaryCodedDecimal.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace PKHeX.Core
+{
+ ///
+ /// 4-bit decimal encoding used by some Generation 1 save file values.
+ ///
+ public static class BinaryCodedDecimal
+ {
+ ///
+ /// Returns a 32-bit signed integer converted from bytes in a Binary Coded Decimal format byte array.
+ ///
+ /// Input byte array to read from.
+ /// Offset to start reading at.
+ /// Length of array to read.
+ public static int ToInt32BE(byte[] input, int offset, int length)
+ {
+ var span = new ReadOnlySpan(input, offset, length);
+ return ToInt32BE(span);
+ }
+
+ ///
+ public static int ToInt32BE(ReadOnlySpan input)
+ {
+ int result = 0;
+ foreach (var b in input)
+ PushDigits(ref result, b);
+ return result;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void PushDigits(ref int result, byte b) => result = (result * 100) + (10 * (b >> 4)) + (b & 0xf);
+
+ ///
+ /// Returns the specified 32-bit signed integer value as an array of Binary Coded Decimal format bytes.
+ ///
+ /// 32-bit signed integer to convert.
+ /// Desired size of returned array.
+ public static byte[] GetBytesBE(int value, int size)
+ {
+ byte[] data = new byte[size];
+ WriteBytesBE(data, value);
+ return data;
+ }
+
+ public static void WriteBytesBE(Span data, int value)
+ {
+ for (int i = 0; i < data.Length; i++)
+ {
+ int p = value % 100;
+ value /= 100;
+ data[^(1+i)] = (byte) (p / 10 << 4 | p % 10);
+ }
+ }
+
+ ///
+ /// Big Endian instead of Little Endian
+ public static int ToInt32LE(byte[] data, int offset, int length)
+ {
+ var span = new ReadOnlySpan(data, offset, length);
+ return ToInt32LE(span);
+ }
+
+ ///
+ public static int ToInt32LE(ReadOnlySpan input)
+ {
+ int result = 0;
+ for (int i = input.Length - 1; i >= 0; i--)
+ PushDigits(ref result, input[i]);
+ return result;
+ }
+
+ ///
+ /// Little Endian instead of Big Endian
+ public static byte[] GetBytesLE(int value, int size)
+ {
+ byte[] data = new byte[size];
+ WriteBytesLE(data, value);
+ return data;
+ }
+
+ ///
+ /// Writes the to the buffer.
+ ///
+ public static void WriteBytesLE(Span data, int value)
+ {
+ for (int i = 0; i < data.Length; i++)
+ {
+ int p = value % 100;
+ value /= 100;
+ data[i] = (byte) (p / 10 << 4 | p % 10);
+ }
+ }
+ }
+}
diff --git a/Tests/PKHeX.Core.Tests/Util/ConvertUtilTests.cs b/Tests/PKHeX.Core.Tests/Util/ConvertUtilTests.cs
index 142538fb1..886c613ae 100644
--- a/Tests/PKHeX.Core.Tests/Util/ConvertUtilTests.cs
+++ b/Tests/PKHeX.Core.Tests/Util/ConvertUtilTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using FluentAssertions;
using Xunit;
@@ -47,5 +48,29 @@ namespace PKHeX.Tests.Util
var remake = Core.Util.GetHexStringFromBytes(convert, 0, convert.Length);
remake.Should().Be(v);
}
+
+ [Theory]
+ [InlineData(0x12345678, 12345678)]
+ public void CheckConvertBCD_Little(uint raw, int expect)
+ {
+ var data = BitConverter.GetBytes(raw);
+ var result = Core.BinaryCodedDecimal.ToInt32LE(data);
+ result.Should().Be(expect);
+
+ var newData = Core.BinaryCodedDecimal.GetBytesLE(result, 4);
+ data.SequenceEqual(newData).Should().BeTrue();
+ }
+
+ [Theory]
+ [InlineData(0x78563412, 12345678)]
+ public void CheckConvertBCD_Big(uint raw, int expect)
+ {
+ var data = BitConverter.GetBytes(raw);
+ var result = Core.BinaryCodedDecimal.ToInt32BE(data);
+ result.Should().Be(expect);
+
+ var newData = Core.BinaryCodedDecimal.GetBytesBE(result, 4);
+ data.SequenceEqual(newData).Should().BeTrue();
+ }
}
}