2023-01-22 04:02:33 +00:00
|
|
|
using System;
|
2021-01-07 23:34:26 +00:00
|
|
|
using System.Collections.Generic;
|
2020-01-20 06:29:50 +00:00
|
|
|
using System.IO;
|
|
|
|
using System.Text;
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
namespace PKHeX.Core;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Utility logic for dumping <see cref="SCBlock"/> lists for external analysis
|
|
|
|
/// </summary>
|
|
|
|
public static class SCBlockUtil
|
2020-01-20 06:29:50 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
public static void ExportAllBlocksAsSingleFile(IReadOnlyList<SCBlock> blocks, string path, SCBlockExportOption option = SCBlockExportOption.All)
|
2020-01-20 06:29:50 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
var data = ExportAllBlocks(blocks, option);
|
|
|
|
File.WriteAllBytes(path, data);
|
|
|
|
}
|
2021-01-07 23:34:26 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static byte[] ExportAllBlocks(IReadOnlyList<SCBlock> blocks, SCBlockExportOption option = SCBlockExportOption.None)
|
|
|
|
{
|
|
|
|
if (option == SCBlockExportOption.None)
|
|
|
|
return SwishCrypto.GetDecryptedRawData(blocks);
|
|
|
|
|
|
|
|
using var stream = new MemoryStream();
|
|
|
|
using var bw = new BinaryWriter(stream);
|
|
|
|
for (var i = 0; i < blocks.Count; i++)
|
|
|
|
ExportBlock(blocks[i], bw, i, option);
|
|
|
|
return stream.ToArray();
|
|
|
|
}
|
2021-01-07 23:34:26 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
private static void ExportBlock(SCBlock block, BinaryWriter bw, int blockIndex, SCBlockExportOption option)
|
|
|
|
{
|
2023-01-22 04:02:33 +00:00
|
|
|
if (option.HasFlag(SCBlockExportOption.DataOnly) && block.Data.Length == 0)
|
2022-06-18 18:04:24 +00:00
|
|
|
return;
|
2021-01-07 23:34:26 +00:00
|
|
|
|
2023-01-22 04:02:33 +00:00
|
|
|
if (option.HasFlag(SCBlockExportOption.FakeHeader))
|
2022-06-18 18:04:24 +00:00
|
|
|
bw.Write($"BLOCK{blockIndex:0000} {block.Key:X8}");
|
2021-01-07 23:34:26 +00:00
|
|
|
|
2023-01-22 04:02:33 +00:00
|
|
|
if (option.HasFlag(SCBlockExportOption.Key))
|
2022-06-18 18:04:24 +00:00
|
|
|
bw.Write(block.Key);
|
2020-01-20 06:29:50 +00:00
|
|
|
|
2023-01-22 04:02:33 +00:00
|
|
|
if (option.HasFlag(SCBlockExportOption.TypeInfo))
|
2020-01-20 06:29:50 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
bw.Write((byte) block.Type);
|
|
|
|
bw.Write((byte) block.SubType);
|
2020-01-20 06:29:50 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
bw.Write(block.Data);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static string GetBlockFileNameWithoutExtension(SCBlock block)
|
|
|
|
{
|
|
|
|
var key = block.Key;
|
|
|
|
var name = $"{key:X8}";
|
|
|
|
if (block.HasValue())
|
|
|
|
name += $" {block.GetValue()}";
|
|
|
|
return name;
|
|
|
|
}
|
2020-01-20 06:29:50 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
public static string GetBlockSummary(SCBlock b)
|
|
|
|
{
|
|
|
|
var sb = new StringBuilder(64);
|
|
|
|
sb.Append("Key: ").AppendFormat("{0:X8}", b.Key).AppendLine();
|
|
|
|
sb.Append("Type: ").Append(b.Type).AppendLine();
|
|
|
|
if (b.Data.Length != 0)
|
|
|
|
sb.Append("Length: ").AppendFormat("{0:X8}", b.Data.Length).AppendLine();
|
|
|
|
|
|
|
|
if (b.SubType != 0)
|
|
|
|
sb.Append("SubType: ").Append(b.SubType).AppendLine();
|
|
|
|
else if (b.HasValue())
|
|
|
|
sb.Append("Value: ").Append(b.GetValue()).AppendLine();
|
|
|
|
|
|
|
|
return sb.ToString();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static List<string> ImportBlocksFromFolder(string path, ISCBlockArray sav)
|
|
|
|
{
|
|
|
|
var failed = new List<string>();
|
|
|
|
var files = Directory.EnumerateFiles(path);
|
|
|
|
foreach (var f in files)
|
2020-01-20 06:29:50 +00:00
|
|
|
{
|
2022-06-18 18:04:24 +00:00
|
|
|
var fn = Path.GetFileNameWithoutExtension(f);
|
2020-01-20 06:29:50 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
// Trim off Value summary if present
|
|
|
|
var space = fn.IndexOf(' ');
|
|
|
|
if (space != -1)
|
|
|
|
fn = fn[..space];
|
2020-01-20 06:29:50 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
var hex = Util.GetHexValue(fn);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
var block = sav.Accessor.GetBlock(hex);
|
|
|
|
var len = block.Data.Length;
|
|
|
|
var fi = new FileInfo(f);
|
|
|
|
if (fi.Length != len)
|
2020-01-20 06:29:50 +00:00
|
|
|
{
|
|
|
|
failed.Add(fn);
|
2022-06-18 18:04:24 +00:00
|
|
|
continue;
|
2020-01-20 06:29:50 +00:00
|
|
|
}
|
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
var data = File.ReadAllBytes(f);
|
|
|
|
block.ChangeData(data);
|
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
failed.Add(fn);
|
|
|
|
}
|
2020-01-20 06:29:50 +00:00
|
|
|
}
|
2021-01-07 23:34:26 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
return failed;
|
2021-01-07 23:34:26 +00:00
|
|
|
}
|
2022-06-18 18:04:24 +00:00
|
|
|
}
|
2021-01-07 23:34:26 +00:00
|
|
|
|
2022-06-18 18:04:24 +00:00
|
|
|
[Flags]
|
|
|
|
public enum SCBlockExportOption
|
|
|
|
{
|
|
|
|
None = 0,
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Will only export blocks with backing data.
|
|
|
|
/// </summary>
|
|
|
|
/// <remarks>Excludes Bool flags from the dump.</remarks>
|
|
|
|
DataOnly = 1,
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Includes the Block Key ahead of the data.
|
|
|
|
/// </summary>
|
|
|
|
Key = 2,
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Includes the Block Info ahead of the data.
|
|
|
|
/// </summary>
|
|
|
|
TypeInfo = 4,
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Includes a fake header indicating which block it is in ASCII.
|
|
|
|
/// </summary>
|
|
|
|
FakeHeader = 8,
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Standard export options.
|
|
|
|
/// </summary>
|
|
|
|
All = DataOnly | Key | TypeInfo | FakeHeader,
|
|
|
|
}
|