From e32bfcde2eafa27e0702f7c78963ffcf4f2bfb17 Mon Sep 17 00:00:00 2001 From: Kurt Date: Mon, 8 Mar 2021 11:39:15 -0800 Subject: [PATCH] Minor simplifications Extract RSBOX checksum logic to checksum class Allocate half as much for gen3 save detect Simplify some expressions for GC save loading (x - size + offset, when x==size) --- PKHeX.Core/Saves/Blocks/BlockInfoRSBOX.cs | 12 ++------ PKHeX.Core/Saves/Util/Checksums.cs | 15 +++++++++- PKHeX.Core/Saves/Util/SaveUtil.cs | 36 ++++++++--------------- 3 files changed, 29 insertions(+), 34 deletions(-) diff --git a/PKHeX.Core/Saves/Blocks/BlockInfoRSBOX.cs b/PKHeX.Core/Saves/Blocks/BlockInfoRSBOX.cs index 5f5c51af4..d6f5386e7 100644 --- a/PKHeX.Core/Saves/Blocks/BlockInfoRSBOX.cs +++ b/PKHeX.Core/Saves/Blocks/BlockInfoRSBOX.cs @@ -40,15 +40,7 @@ private uint GetChecksum(byte[] data) int start = Offset + 4; int end = start + Length - 4; - return GetChecksum(data, start, end); - } - - private static uint GetChecksum(byte[] data, int start, int end) - { - ushort chk = 0; // initial value - for (int j = start; j < end; j += 2) - chk += BigEndian.ToUInt16(data, j); - return (uint)(chk << 16 | (ushort)(0xF004 - chk)); + return Checksums.CheckSum16BigInvert(data, start, end); } } -} \ No newline at end of file +} diff --git a/PKHeX.Core/Saves/Util/Checksums.cs b/PKHeX.Core/Saves/Util/Checksums.cs index 99969f9d4..d57a7e28d 100644 --- a/PKHeX.Core/Saves/Util/Checksums.cs +++ b/PKHeX.Core/Saves/Util/Checksums.cs @@ -129,5 +129,18 @@ public static ushort CheckSum16(byte[] data, int start, int length, ushort initi /// Initial value for checksum /// Checksum public static ushort CheckSum32(byte[] data, uint initial = 0) => CheckSum32(data, 0, data.Length, initial); + + /// Calculates the 32bit checksum over an input byte array. Used in GC R/S BOX. + /// Input byte array + /// Offset to start checksum at + /// Exclusive end offset to finish the checksum at + /// Checksum + public static uint CheckSum16BigInvert(byte[] data, int start, int end) + { + ushort chk = 0; // initial value + for (int i = start; i < end; i += 2) + chk += BigEndian.ToUInt16(data, i); + return (uint)(chk << 16 | (ushort)(0xF004 - chk)); + } } -} \ No newline at end of file +} diff --git a/PKHeX.Core/Saves/Util/SaveUtil.cs b/PKHeX.Core/Saves/Util/SaveUtil.cs index 6e607ab04..98213b48f 100644 --- a/PKHeX.Core/Saves/Util/SaveUtil.cs +++ b/PKHeX.Core/Saves/Util/SaveUtil.cs @@ -273,20 +273,20 @@ private static GameVersion GetIsG3SAV(byte[] data) const int blockCount = 14; const int blockSize = 0x1000; int ofs = blockCount * blockSize * s; - int[] order = new int[blockCount]; + var order = new short[blockCount]; for (int i = 0; i < order.Length; i++) - order[i] = BitConverter.ToUInt16(data, (i * blockSize) + 0xFF4 + ofs); + order[i] = BitConverter.ToInt16(data, (i * blockSize) + 0xFF4 + ofs); - if (Array.FindIndex(order, i => i > 0xD) >= 0) // invalid block ID + if (Array.FindIndex(order, i => (uint)i > 0xD) >= 0) // invalid block ID continue; - int block0 = Array.IndexOf(order, 0); + int block0 = Array.IndexOf(order, (short)0); // Sometimes not all blocks are present (start of game), yielding multiple block0's. // Real 0th block comes before block1. if (order[0] == 1 && block0 != order.Length - 1) continue; - if (Array.FindIndex(order, v => v != 0) < 0) // all blocks are 0 + if (Array.TrueForAll(order, v => v == 0)) // all blocks are 0 continue; // Detect RS/E/FRLG return SAV3.GetVersion(data, (blockSize * block0) + ofs); @@ -302,21 +302,11 @@ private static GameVersion GetIsG3BOXSAV(byte[] data) if (data.Length is not SIZE_G3BOX) return Invalid; - byte[] sav = data; - // Verify first checksum - ushort chk = 0; // initial value - var ofs = data.Length - SIZE_G3BOX + 0x2000; - for (int i = 0x4; i < 0x1FFC; i += 2) - chk += BigEndian.ToUInt16(sav, ofs + i); - - ushort chkA = chk; - ushort chkB = (ushort)(0xF004 - chkA); - - ushort CHK_A = BigEndian.ToUInt16(sav, ofs + 0); - ushort CHK_B = BigEndian.ToUInt16(sav, ofs + 2); - - return CHK_A == chkA && CHK_B == chkB ? RSBOX : Invalid; + const int offset = 0x2000; + var chk = Checksums.CheckSum16BigInvert(data, offset + 4, offset + 0x1FFC); + var actual = BigEndian.ToUInt32(data, offset); + return chk == actual ? RSBOX : Invalid; } /// Checks to see if the data belongs to a Colosseum save @@ -328,10 +318,10 @@ private static GameVersion GetIsG3COLOSAV(byte[] data) return Invalid; // Check the intro bytes for each save slot - int offset = data.Length - SIZE_G3COLO; + const int offset = 0x6000; for (int i = 0; i < 3; i++) { - var ofs = 0x6000 + offset + (0x1E000 * i); + var ofs = offset + (0x1E000 * i); if (BitConverter.ToUInt32(data, ofs) != 0x00000101) return Invalid; } @@ -347,10 +337,10 @@ private static GameVersion GetIsG3XDSAV(byte[] data) return Invalid; // Check the intro bytes for each save slot - int offset = data.Length - SIZE_G3XD; + const int offset = 0x6000; for (int i = 0; i < 2; i++) { - var ofs = 0x6000 + offset + (0x28000 * i); + var ofs = offset + (0x28000 * i); if ((BitConverter.ToUInt32(data, ofs) & 0xFFFE_FFFF) != 0x00000101) return Invalid; }