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;
}
}
}