using System; using System.Globalization; using System.Linq; namespace BizHawk.Client.Common.cheats { // TODO: public static class GbaGameSharkDecoder { private static readonly uint[] GameSharkSeeds = { 0x09F4FBBDU, 0x9681884AU, 0x352027E9U, 0xF3DEE5A7U }; private static readonly uint[] ProActionReplaySeeds = { 0x7AA9648FU, 0x7FAE6994U, 0xC0EFAAD5U, 0x42712C57U }; private static string Decrypt(string code) { var op1 = uint.Parse(code.Remove(8, 9), NumberStyles.HexNumber); var op2 = uint.Parse(code.Remove(0, 9), NumberStyles.HexNumber); uint sum = 0xC6EF3720; // Tiny Encryption Algorithm for (int i = 0; i < 32; ++i) { op2 -= ((op1 << 4) + GameSharkSeeds[2]) ^ (op1 + sum) ^ ((op1 >> 5) + GameSharkSeeds[3]); op1 -= ((op2 << 4) + GameSharkSeeds[0]) ^ (op2 + sum) ^ ((op2 >> 5) + GameSharkSeeds[1]); sum -= 0x9E3779B9; } return $"{op1:X8} {op2:X8}"; } // TODO: When to use this? private static string DecryptPro(string code) { var sum = 0xC6EF3720; var op1 = uint.Parse(code.Remove(8, 9), NumberStyles.HexNumber); var op2 = uint.Parse(code.Remove(0, 9), NumberStyles.HexNumber); for (int j = 0; j < 32; ++j) { op2 -= ((op1 << 4) + ProActionReplaySeeds[2]) ^ (op1 + sum) ^ ((op1 >> 5) + ProActionReplaySeeds[3]); op1 -= ((op2 << 4) + ProActionReplaySeeds[0]) ^ (op2 + sum) ^ ((op2 >> 5) + ProActionReplaySeeds[1]); sum -= 0x9E3779B9; } return $"{op1:X8} {op2:X8}"; } public static IDecodeResult Decode(string code) { if (code == null) { throw new ArgumentNullException(nameof(code)); } if (code.Length != 17) { code = Decrypt(code); } if (code.IndexOf(" ") != 9 || code.Length != 17) { return new InvalidCheatCode("All GBA GameShark Codes need to be 17 characters in length with a space after the first eight."); } var result = new DecodeResult { Size = code.First() switch { '0' => WatchSize.Byte, '1' => WatchSize.Word, '2' => WatchSize.DWord, '3' => WatchSize.DWord, '6' => WatchSize.Word, _ => WatchSize.Byte } }; result.Address = int.Parse(GetLast(code, (int)result.Size), NumberStyles.HexNumber); result.Value = int.Parse(code.Substring(1, 8)); return result; } private static string GetLast(string str, int length) { return length >= str.Length ? str : str.Substring(str.Length - length); } } }