From 2c8e0bc8f776fd2139d592674fabf7e2059707c5 Mon Sep 17 00:00:00 2001 From: Kurt Date: Wed, 30 Sep 2020 22:46:07 -0700 Subject: [PATCH] Add automatic byteswap --- PKHeX.Core/Saves/SAV1Stadium.cs | 36 +++++++++++---------- PKHeX.Core/Saves/SAV1StadiumJ.cs | 29 +++++++++++------ PKHeX.Core/Saves/Util/StadiumUtil.cs | 48 ++++++++++++++++++++++++++++ PKHeX.Core/Util/BigEndian.cs | 18 +++++++++++ 4 files changed, 104 insertions(+), 27 deletions(-) create mode 100644 PKHeX.Core/Saves/Util/StadiumUtil.cs diff --git a/PKHeX.Core/Saves/SAV1Stadium.cs b/PKHeX.Core/Saves/SAV1Stadium.cs index 8353ebf1d..203f51942 100644 --- a/PKHeX.Core/Saves/SAV1Stadium.cs +++ b/PKHeX.Core/Saves/SAV1Stadium.cs @@ -52,6 +52,16 @@ public override byte[] SetString(string value, int maxLength, int PadToSize = 0, public override int GetPartyOffset(int slot) => -1; + private readonly bool IsPairSwapped; + + protected override byte[] GetFinalData() + { + var result = base.GetFinalData(); + if (IsPairSwapped) + BigEndian.SwapBytes32(result = (byte[])result.Clone()); + return result; + } + public override bool ChecksumsValid => GetBoxChecksumsValid(); protected override void SetChecksums() => SetBoxChecksums(); @@ -104,6 +114,12 @@ protected override PKM GetPKM(byte[] data) public SAV1Stadium(byte[] data, bool japanese) : base(data) { Japanese = japanese; + var swap = StadiumUtil.IsMagicPresentSwap(data, TeamSize, MAGIC_POKE); + if (swap) + { + BigEndian.SwapBytes32(Data); + IsPairSwapped = true; + } Box = 0xC000; } @@ -163,34 +179,20 @@ public override void WriteBoxSlot(PKM pkm, byte[] data, int offset) base.WriteBoxSlot(pkm, Data, offset); } - private const int MAGIC_POKE = 0x454B4F50; + private const uint MAGIC_POKE = 0x454B4F50; public static bool IsStadiumU(byte[] data) { if (data.Length != SaveUtil.SIZE_G1STAD) return false; - - // Check footers of first few teams to see if the magic value is there. - for (int i = 0; i < 10; i++) - { - if (BitConverter.ToUInt32(data, TeamSizeU - ListFooterSize + (i * TeamSizeU)) != MAGIC_POKE) // POKE - return false; - } - return true; + return StadiumUtil.IsMagicPresentEither(data, TeamSizeU, MAGIC_POKE); } public static bool IsStadiumJ(byte[] data) { if (data.Length != SaveUtil.SIZE_G1STAD) return false; - - // Check footers of first few teams to see if the magic value is there. - for (int i = 0; i < 10; i++) - { - if (BitConverter.ToUInt32(data, TeamSizeJ - ListFooterSize + (i * TeamSizeJ)) != MAGIC_POKE) // POKE - return false; - } - return true; + return StadiumUtil.IsMagicPresentEither(data, TeamSizeJ, MAGIC_POKE); } } diff --git a/PKHeX.Core/Saves/SAV1StadiumJ.cs b/PKHeX.Core/Saves/SAV1StadiumJ.cs index cfe16e4a4..4c97c2316 100644 --- a/PKHeX.Core/Saves/SAV1StadiumJ.cs +++ b/PKHeX.Core/Saves/SAV1StadiumJ.cs @@ -14,7 +14,7 @@ public class SAV1StadiumJ : SaveFile, ILangDeviantSave // Required since PK1 logic comparing a save file assumes the save file can be U/J public int SaveRevision => 0; - public string SaveRevisionString => string.Empty; + public string SaveRevisionString => "0"; // so we're different from Japanese SAV1Stadium naming... public bool Japanese => true; public bool Korean => false; @@ -54,6 +54,16 @@ public override byte[] SetString(string value, int maxLength, int PadToSize = 0, public override int GetPartyOffset(int slot) => -1; + private readonly bool IsPairSwapped; + + protected override byte[] GetFinalData() + { + var result = base.GetFinalData(); + if (IsPairSwapped) + BigEndian.SwapBytes32(result = (byte[])result.Clone()); + return result; + } + public override bool ChecksumsValid => GetBoxChecksumsValid(); protected override void SetChecksums() => SetBoxChecksums(); @@ -102,6 +112,12 @@ protected override PKM GetPKM(byte[] data) public SAV1StadiumJ(byte[] data) : base(data) { + var swap = StadiumUtil.IsMagicPresentSwap(data, TeamSizeJ, MAGIC_POKE); + if (swap) + { + BigEndian.SwapBytes32(Data); + IsPairSwapped = true; + } Box = 0x2500; } @@ -156,20 +172,13 @@ public override void WriteBoxSlot(PKM pkm, byte[] data, int offset) base.WriteBoxSlot(pkm, Data, offset); } - private const int MAGIC_POKE = 0x454B4F50; + private const uint MAGIC_POKE = 0x454B4F50; public static bool IsStadiumJ(byte[] data) { if (data.Length != SaveUtil.SIZE_G1STADJ) return false; - - // Check footers of first few teams to see if the magic value is there. - for (int i = 0; i < 10; i++) - { - if (BitConverter.ToUInt32(data, TeamSizeJ - ListFooterSize + (i * TeamSizeJ)) != MAGIC_POKE) // POKE - return false; - } - return true; + return StadiumUtil.IsMagicPresentEither(data, TeamSizeJ, MAGIC_POKE); } } } diff --git a/PKHeX.Core/Saves/Util/StadiumUtil.cs b/PKHeX.Core/Saves/Util/StadiumUtil.cs new file mode 100644 index 000000000..53b64f53c --- /dev/null +++ b/PKHeX.Core/Saves/Util/StadiumUtil.cs @@ -0,0 +1,48 @@ +using System; + +namespace PKHeX.Core +{ + public static class StadiumUtil + { + public static bool IsMagicPresentEither(byte[] data, int size, uint magic) + { + if (IsMagicPresent(data, size, magic)) + return true; + + if (IsMagicPresentSwap(data, size, magic)) + return true; + + return false; + } + + public static bool IsMagicPresent(byte[] data, int size, uint magic) + { + // Check footers of first few teams to see if the magic value is there. + for (int i = 0; i < 10; i++) + { + if (BitConverter.ToUInt32(data, size - 6 + (i * size)) != magic) + return false; + } + return true; + } + + public static bool IsMagicPresentSwap(byte[] data, int size, uint magic) + { + // Check footers of first few teams to see if the magic value is there. + var left = (ushort)magic; + var right = (ushort)(magic >> 16); + left = (ushort)((left >> 8) | (left << 8)); + right = (ushort)((right >> 8) | (right << 8)); + + for (int i = 0; i < 10; i++) + { + var ofs = size - 6 + (i * size); + if (BitConverter.ToUInt16(data, ofs - 2) != left) // OP + return false; + if (BitConverter.ToUInt16(data, ofs + 4) != right) // EK + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Util/BigEndian.cs b/PKHeX.Core/Util/BigEndian.cs index 73500594a..693596751 100644 --- a/PKHeX.Core/Util/BigEndian.cs +++ b/PKHeX.Core/Util/BigEndian.cs @@ -75,6 +75,24 @@ private static byte[] Invert(byte[] data) return data; } + /// + /// Swaps byte ordering in a byte array based on 32bit value writes. + /// + /// The is reversed in-place. + public static void SwapBytes32(byte[] data) + { + for (int i = 0; i < data.Length; i += 4) + { + byte tmp = data[0 + i]; + data[0 + i] = data[3 + i]; + data[3 + i] = tmp; + + byte tmp1 = data[1 + i]; + data[1 + i] = data[2 + i]; + data[2 + i] = tmp1; + } + } + /// /// Returns a 32-bit signed integer converted from bytes in a Binary Coded Decimal format byte array. ///