using System; namespace PKHeX.Core { /// /// Gen6+ Block Info /// public sealed class BlockInfo3DS : BlockInfo { public ushort Checksum; private int BlockInfoOffset; private readonly Func CheckFunc; public BlockInfo3DS() { } private BlockInfo3DS(Func func) => CheckFunc = func; private int ChecksumOffset => BlockInfoOffset + 6 + ((int)ID * 8); private ushort GetChecksum(byte[] data) => CheckFunc(data, Offset, Length); protected override bool ChecksumValid(byte[] data) { ushort chk = GetChecksum(data); var old = BitConverter.ToUInt16(data, ChecksumOffset); return chk == old; } protected override void SetChecksum(byte[] data) { ushort chk = GetChecksum(data); BitConverter.GetBytes(chk).CopyTo(data, ChecksumOffset); } /// /// Gets the table for the input . /// /// Complete data array /// Offset the starts at. /// Checksum method for validating each block. public static BlockInfo[] GetBlockInfoData(byte[] data, out int blockInfoOffset, Func CheckFunc) { blockInfoOffset = data.Length - 0x200 + 0x10; if (BitConverter.ToUInt32(data, blockInfoOffset) != SaveUtil.BEEF) blockInfoOffset -= 0x200; // No savegames have more than 0x3D blocks, maybe in the future? int len = data.Length; return GetBlockInfo(data, ref blockInfoOffset, CheckFunc, len); } /// /// Gets the table for the input . /// /// Complete data array /// Offset the starts at. /// Checksum method for validating each block. /// public static BlockInfo[] GetBlockInfoData(byte[] data, ref int blockInfoOffset, Func CheckFunc, int dataLength) { if (BitConverter.ToUInt32(data, blockInfoOffset) != SaveUtil.BEEF) blockInfoOffset -= 0x200; // No savegames have more than 0x3D blocks, maybe in the future? return GetBlockInfo(data, ref blockInfoOffset, CheckFunc, dataLength); } private static BlockInfo[] GetBlockInfo(byte[] data, ref int blockInfoOffset, Func CheckFunc, int dataLength) { int count = (dataLength - blockInfoOffset - 0x8) / 8; blockInfoOffset += 4; var Blocks = new BlockInfo[count]; int CurrentPosition = 0; for (int i = 0; i < Blocks.Length; i++) { int ofs = i * 8; Blocks[i] = new BlockInfo3DS(CheckFunc) { Offset = CurrentPosition, Length = BitConverter.ToInt32(data, blockInfoOffset + ofs + 0), ID = BitConverter.ToUInt16(data, blockInfoOffset + ofs + 4), Checksum = BitConverter.ToUInt16(data, blockInfoOffset + ofs + 6), BlockInfoOffset = blockInfoOffset }; // Expand out to nearest 0x200 var remainder = Blocks[i].Length & 0x1FF; CurrentPosition += remainder == 0 ? Blocks[i].Length : Blocks[i].Length + 0x200 - remainder; if (Blocks[i].ID != 0 || i == 0) continue; count = i; break; } // Fix Final Array Lengths Array.Resize(ref Blocks, count); return Blocks; } } }