using System; using System.Collections.Generic; namespace PKHeX.Core; public abstract class BlockInfo { // General public uint ID { get; protected init; } public int Offset { get; protected init; } public int Length { get; protected init; } public string Summary => $"{ID:00}: {Offset:X5}-{Offset + Length - 1:X5}, {Length:X5}"; protected abstract bool ChecksumValid(ReadOnlySpan data); protected abstract void SetChecksum(Span data); /// /// Checks if the currently written checksum values are valid. /// /// Block info objects used for offset/length /// Complete data array /// True if checksums are valid, false if anything is invalid. public static bool GetChecksumsValid(IEnumerable blocks, ReadOnlySpan data) { foreach (var b in blocks) { if (b.Length + b.Offset > data.Length) return false; if (!b.ChecksumValid(data)) return false; } return true; } /// /// Applies checksums to the object based on the input blocks. /// /// Block info objects used for offset/length /// Complete data array public static void SetChecksums(IEnumerable blocks, Span data) { foreach (var b in blocks) b.SetChecksum(data); } /// /// Gets information pertaining to the checksum data for diagnostic purposes. /// /// Block info objects used for offset/length /// Complete data array /// Multi-line string with data. public static string GetChecksumInfo(IReadOnlyList blocks, Span data) { var invalid = GetInvalidBlockCount(blocks, data, out var list); list.Add($"SAV: {blocks.Count - invalid}/{blocks.Count}"); return string.Join(Environment.NewLine, list); } private static int GetInvalidBlockCount(IReadOnlyList blocks, Span data, out List list) { int invalid = 0; list = new List(); for (int i = 0; i < blocks.Count; i++) { if (blocks[i].Length + blocks[i].Offset > data.Length) { list.Add($"Block {i} Invalid Offset/Length."); return invalid; } if (blocks[i].ChecksumValid(data)) continue; invalid++; list.Add($"Invalid: {i:X2} @ Region {blocks[i].Offset:X5}"); } return invalid; } } public static partial class Extensions { public static bool GetChecksumsValid(this IEnumerable blocks, Span data) => BlockInfo.GetChecksumsValid(blocks, data); public static void SetChecksums(this IEnumerable blocks, Span data) => BlockInfo.SetChecksums(blocks, data); public static string GetChecksumInfo(this IReadOnlyList blocks, Span data) => BlockInfo.GetChecksumInfo(blocks, data); }