mirror of
https://github.com/kwsch/PKHeX
synced 2024-12-24 19:33:10 +00:00
47071b41f3
Existing `get`/`set` logic is flawed in that it doesn't work on Big Endian operating systems, and it allocates heap objects when it doesn't need to. `System.Buffers.Binary.BinaryPrimitives` in the `System.Memory` NuGet package provides both Little Endian and Big Endian methods to read and write data; all the `get`/`set` operations have been reworked to use this new API. This removes the need for PKHeX's manual `BigEndian` class, as all functions are already covered by the BinaryPrimitives API. The `StringConverter` has now been rewritten to accept a Span to read from & write to, no longer requiring a temporary StringBuilder. Other Fixes included: - The Super Training UI for Gen6 has been reworked according to the latest block structure additions. - Cloning a Stadium2 Save File now works correctly (opening from the Folder browser list). - Checksum & Sanity properties removed from parent PKM class, and is now implemented via interface.
141 lines
7.5 KiB
C#
141 lines
7.5 KiB
C#
using System;
|
|
|
|
namespace PKHeX.Core;
|
|
|
|
/// <summary>
|
|
/// Logic for converting a <see cref="string"/> from Generation 1 & 2 games to Generation 7.
|
|
/// </summary>
|
|
public static class StringConverter12Transporter
|
|
{
|
|
private const ushort Terminator = 0;
|
|
|
|
/// <summary>
|
|
/// Converts Generation 1 encoded data the same way Bank converts.
|
|
/// </summary>
|
|
/// <param name="data">Generation 1 encoded data.</param>
|
|
/// <param name="jp">Data source is Japanese.</param>
|
|
/// <returns>Decoded string.</returns>
|
|
public static string GetString(ReadOnlySpan<byte> data, bool jp)
|
|
{
|
|
Span<char> result = stackalloc char[data.Length];
|
|
int length = LoadString1(data, result, jp);
|
|
return new string(result[..length].ToArray());
|
|
}
|
|
|
|
private static int LoadString1(ReadOnlySpan<byte> data, Span<char> result, bool jp)
|
|
{
|
|
var table = jp ? jp_table : us_table;
|
|
int i = 0;
|
|
for (; i < data.Length; i++)
|
|
{
|
|
var b = data[i];
|
|
if (b == 0)
|
|
break;
|
|
|
|
var value = table[b];
|
|
if (value == Terminator)
|
|
break;
|
|
|
|
result[i] = (char)value;
|
|
}
|
|
CheckKata(result[..i]);
|
|
return i;
|
|
}
|
|
|
|
private static void CheckKata(Span<char> chars)
|
|
{
|
|
bool isAnyKata = IsKata(chars);
|
|
if (!isAnyKata)
|
|
return;
|
|
|
|
if (!IsHiragana(chars))
|
|
return;
|
|
|
|
var span = Katakana.AsSpan();
|
|
for (int i = 0; i < chars.Length; i++)
|
|
{
|
|
int index = span.IndexOf(chars[i]);
|
|
if (index == -1)
|
|
continue;
|
|
chars[i] = Hiragana[index];
|
|
}
|
|
}
|
|
|
|
private static bool IsKata(ReadOnlySpan<char> chars)
|
|
{
|
|
var span = Katakana.AsSpan();
|
|
foreach (var c in chars)
|
|
{
|
|
if (span.IndexOf(c) != -1)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static bool IsHiragana(ReadOnlySpan<char> chars)
|
|
{
|
|
foreach (var c in chars)
|
|
{
|
|
if ((uint)(c - 0x3041) < 0x53)
|
|
return true;
|
|
if ((uint)(c - 0x30A1) < 0x56)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static readonly char[] Katakana = { 'ベ', 'ペ', 'ヘ', 'リ' };
|
|
private static readonly char[] Hiragana = { 'べ', 'ぺ', 'へ', 'り' };
|
|
|
|
/// <summary>
|
|
/// International 1->7 character translation table
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Exported from Gen1's VC string transferring, with manual modifications for the two permitted accent marks:
|
|
/// <br>0xC1 at arr[0xBF] = Á (Spanish In-game Trade Voltorb, FALCÁN)</br>
|
|
/// <br>0xCD at arr[0xC9] = Í (Spanish In-game Trade Shuckle, MANÍA)</br>
|
|
/// <br>All other new language sensitive re-mapping (or lack thereof) are inaccessible via the character entry screen.</br>
|
|
/// </remarks>
|
|
private static readonly ushort[] us_table =
|
|
{
|
|
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // 0
|
|
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // 1
|
|
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // 2
|
|
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // 3
|
|
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // 4
|
|
0x0000, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // 5
|
|
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // 6
|
|
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // 7
|
|
0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, // 8
|
|
0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x0028, 0x0029, 0x003A, 0x003B, 0x0028, 0x0029, // 9
|
|
0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, // A
|
|
0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x00C1, // B
|
|
0x00C4, 0x00D6, 0x00DC, 0x00E4, 0x00F6, 0x00FC, 0x0020, 0x0020, 0x0020, 0x00CD, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // C
|
|
0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // D
|
|
0x0020, 0x0050, 0x004D, 0x002D, 0x0020, 0x0020, 0x003F, 0x0021, 0x002D, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0xE08E, // E
|
|
0x0020, 0x0078, 0x002E, 0x002F, 0x002C, 0xE08F, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, // F
|
|
};
|
|
|
|
/// <summary>
|
|
/// Japanese 1->7 character translation table
|
|
/// </summary>
|
|
private static readonly ushort[] jp_table =
|
|
{
|
|
0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x30AC, 0x30AE, 0x30B0, 0x30B2, 0x30B4, 0x30B6, 0x30B8, 0x30BA, 0x30BC, 0x30BE, 0x30C0, // 0
|
|
0x30C2, 0x30C5, 0x30C7, 0x30C9, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x30D0, 0x30D3, 0x30D6, 0x30DC, 0x3000, 0x3000, 0x3000, // 1
|
|
0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x304C, 0x304E, 0x3050, 0x3052, 0x3054, 0x3056, 0x3058, 0x305A, 0x305C, 0x305E, // 2
|
|
0x3060, 0x3062, 0x3065, 0x3067, 0x3069, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3070, 0x3073, 0x3076, 0x30D9, 0x307C, 0x3000, // 3
|
|
0x30D1, 0x30D4, 0x30D7, 0x30DD, 0x3071, 0x3074, 0x3077, 0x30DA, 0x307D, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, // 4
|
|
0x0000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, // 5
|
|
0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, // 6
|
|
0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, // 7
|
|
0x30A2, 0x30A4, 0x30A6, 0x30A8, 0x30AA, 0x30AB, 0x30AD, 0x30AF, 0x30B1, 0x30B3, 0x30B5, 0x30B7, 0x30B9, 0x30BB, 0x30BD, 0x30BF, // 8
|
|
0x30C1, 0x30C4, 0x30C6, 0x30C8, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D2, 0x30D5, 0x30DB, 0x30DE, 0x30DF, 0x30E0, // 9
|
|
0x30E1, 0x30E2, 0x30E4, 0x30E6, 0x30E8, 0x30E9, 0x30EB, 0x30EC, 0x30ED, 0x30EF, 0x30F2, 0x30F3, 0x30C3, 0x30E3, 0x30E5, 0x30E7, // A
|
|
0x30A3, 0x3042, 0x3044, 0x3046, 0x3048, 0x304A, 0x304B, 0x304D, 0x304F, 0x3051, 0x3053, 0x3055, 0x3057, 0x3059, 0x305B, 0x305D, // B
|
|
0x305F, 0x3061, 0x3064, 0x3066, 0x3068, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3072, 0x3075, 0x30D8, 0x307B, 0x307E, // C
|
|
0x307F, 0x3080, 0x3081, 0x3082, 0x3084, 0x3086, 0x3088, 0x3089, 0x30EA, 0x308B, 0x308C, 0x308D, 0x308F, 0x3092, 0x3093, 0x3063, // D
|
|
0x3083, 0x3085, 0x3087, 0x30FC, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x30A1, 0x30A5, 0x30A7, 0x3000, 0x3000, 0x3000, 0x2642, // E
|
|
0x3000, 0x3000, 0x3000, 0x3000, 0x30A9, 0x2640, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, // F
|
|
};
|
|
}
|