diff --git a/PKHeX.Core/MysteryGifts/PGF.cs b/PKHeX.Core/MysteryGifts/PGF.cs index f37aae9bf..27ae4bafb 100644 --- a/PKHeX.Core/MysteryGifts/PGF.cs +++ b/PKHeX.Core/MysteryGifts/PGF.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; namespace PKHeX.Core { @@ -52,8 +51,8 @@ public sealed class PGF : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I public string Nickname { - get => Util.TrimFromFFFF(Encoding.Unicode.GetString(Data, 0x1E, 0x16)); - set => Encoding.Unicode.GetBytes(value.PadRight(0xB, (char)0xFFFF)).CopyTo(Data, 0x1E); + get => StringConverter.GetString5(Data, 0x1E, 11 * 2); + set => StringConverter.SetString5(value, 11, 11, (char)0xFFFF).CopyTo(Data, 0x1E); } public int Nature { get => (sbyte)Data[0x34]; set => Data[0x34] = (byte)value; } @@ -76,9 +75,11 @@ public string Nickname public int IV_SPA { get => Data[0x47]; set => Data[0x47] = (byte)value; } public int IV_SPD { get => Data[0x48]; set => Data[0x48] = (byte)value; } // Unused 0x49 - public override string OT_Name { - get => Util.TrimFromFFFF(Encoding.Unicode.GetString(Data, 0x4A, 0x10)); - set => Encoding.Unicode.GetBytes(value.PadRight(0x08, (char)0xFFFF)).CopyTo(Data, 0x4A); } + public override string OT_Name + { + get => StringConverter.GetString5(Data, 0x4A, 8 * 2); + set => StringConverter.SetString5(value, 8, 8, (char)0xFFFF).CopyTo(Data, 0x4A); + } public int OTGender { get => Data[0x5A]; set => Data[0x5A] = (byte)value; } public override int Level { get => Data[0x5B]; set => Data[0x5C] = (byte)value; } @@ -86,8 +87,8 @@ public string Nickname // Unused 0x5D 0x5E 0x5F public override string CardTitle { - get => Util.TrimFromFFFF(Encoding.Unicode.GetString(Data, 0x60, 0x4A)); - set => Encoding.Unicode.GetBytes((value + '\uFFFF').PadRight(0x4A / 2, '\0')).CopyTo(Data, 0x60); + get => StringConverter.GetString5(Data, 0x60, 37 * 2); + set => StringConverter.SetString5(value + '\uFFFF', 37, 37, 0).CopyTo(Data, 0x60); } // Card Attributes diff --git a/PKHeX.Core/MysteryGifts/PL6.cs b/PKHeX.Core/MysteryGifts/PL6.cs index a33bfac22..9e5a44685 100644 --- a/PKHeX.Core/MysteryGifts/PL6.cs +++ b/PKHeX.Core/MysteryGifts/PL6.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; namespace PKHeX.Core { @@ -33,7 +32,7 @@ public sealed class PL6 /// /// Name of data source /// - public string Origin { get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x01, 0x6E)); set => Encoding.Unicode.GetBytes(value.PadRight(54 + 1, '\0')).CopyTo(Data, 0x01); } + public string Origin { get => StringConverter.GetString6(Data, 0x01, 110); set => StringConverter.SetString6(value, 54, 55).CopyTo(Data, 0x01); } // Pokemon transfer flags? public uint Flags_1 { get => BitConverter.ToUInt32(Data, 0x099); set => BitConverter.GetBytes(value).CopyTo(Data, 0x099); } @@ -101,8 +100,8 @@ public sealed class PL6_PKM : IRibbonSetEvent3, IRibbonSetEvent4 public string Nickname { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x1E, 0x1A)); - set => Encoding.Unicode.GetBytes(value.PadRight(12 + 1, '\0')).CopyTo(Data, 0x1E); + get => StringConverter.GetString6(Data, 0x1E, 0x1A); + set => StringConverter.SetString6(value, 12, 13).CopyTo(Data, 0x1E); } public int Nature { get => Data[0x38]; set => Data[0x38] = (byte)value; } @@ -131,8 +130,8 @@ public string Nickname public string OT { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x4E, 0x1A)); - set => Encoding.Unicode.GetBytes(value.PadRight(value.Length + 1, '\0')).CopyTo(Data, 0x4E); + get => StringConverter.GetString6(Data, 0x4E, 0x1A); + set => StringConverter.SetString6(value, 12, 13).CopyTo(Data, 0x4E); } public int Level { get => Data[0x68]; set => Data[0x68] = (byte)value; } diff --git a/PKHeX.Core/MysteryGifts/WB7.cs b/PKHeX.Core/MysteryGifts/WB7.cs index 81c2a59bf..1b4b9c4fc 100644 --- a/PKHeX.Core/MysteryGifts/WB7.cs +++ b/PKHeX.Core/MysteryGifts/WB7.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; namespace PKHeX.Core { @@ -42,8 +41,8 @@ public override int CardID public override string CardTitle { // Max len 36 char, followed by null terminator - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, CardStart + 2, 72)); - set => Encoding.Unicode.GetBytes(value.PadRight(36, '\0')).CopyTo(Data, CardStart + 2); + get => StringConverter.GetString7(Data, CardStart + 2, 0x4A); + set => StringConverter.SetString7b(value, 36, 2, 37).CopyTo(Data, CardStart + 2); } private uint RawDate @@ -275,11 +274,11 @@ public override IReadOnlyList Relearn public bool IsNicknamed => false; public int Language => 2; - public string GetNickname(int language) => Util.TrimFromZero(Encoding.Unicode.GetString(Data, GetNicknameOffset(language), 0x1A)); - public void SetNickname(int language, string value) => Encoding.Unicode.GetBytes(value.PadRight(0x1A / 2, '\0')).CopyTo(Data, GetNicknameOffset(language)); + public string GetNickname(int language) => StringConverter.GetString7(Data, GetNicknameOffset(language), 0x1A); + public void SetNickname(int language, string value) => StringConverter.SetString7b(value, 12, 2, 13).CopyTo(Data, GetNicknameOffset(language)); - public string GetOT(int language) => Util.TrimFromZero(Encoding.Unicode.GetString(Data, GetOTOffset(language), 0x1A)); - public void SetOT(int language, string value) => Encoding.Unicode.GetBytes(value.PadRight(0x1A / 2, '\0')).CopyTo(Data, GetOTOffset(language)); + public string GetOT(int language) => StringConverter.GetString7(Data, GetOTOffset(language), 0x1A); + public void SetOT(int language, string value) => StringConverter.SetString7b(value, 12, 2, 13).CopyTo(Data, GetOTOffset(language)); private static int GetNicknameOffset(int language) { diff --git a/PKHeX.Core/MysteryGifts/WC6.cs b/PKHeX.Core/MysteryGifts/WC6.cs index b2056be53..d307153e4 100644 --- a/PKHeX.Core/MysteryGifts/WC6.cs +++ b/PKHeX.Core/MysteryGifts/WC6.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; namespace PKHeX.Core { @@ -41,8 +40,8 @@ public override int CardID public override string CardTitle { // Max len 36 char, followed by null terminator - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 2, 72)); - set => Encoding.Unicode.GetBytes(value.PadRight(36, '\0')).CopyTo(Data, 2); + get => StringConverter.GetString6(Data, 2, 0x4A); + set => StringConverter.SetString6(value, 36, 37).CopyTo(Data, 2); } internal uint RawDate @@ -142,8 +141,8 @@ private uint Day public string Nickname { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x86, 0x1A)); - set => Encoding.Unicode.GetBytes(value.PadRight(12 + 1, '\0')).CopyTo(Data, 0x86); + get => StringConverter.GetString6(Data, 0x86, 0x1A); + set => StringConverter.SetString6(value, 12, 13).CopyTo(Data, 0x86); } public int Nature { get => (sbyte)Data[0xA0]; set => Data[0xA0] = (byte)value; } @@ -171,8 +170,8 @@ public string Nickname public override string OT_Name { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0xB6, 0x1A)); - set => Encoding.Unicode.GetBytes(value.PadRight(value.Length + 1, '\0')).CopyTo(Data, 0xB6); + get => StringConverter.GetString6(Data, 0xB6, 0x1A); + set => StringConverter.SetString6(value, 12, 13).CopyTo(Data, 0xB6); } public override int Level { get => Data[0xD0]; set => Data[0xD0] = (byte)value; } diff --git a/PKHeX.Core/MysteryGifts/WC7.cs b/PKHeX.Core/MysteryGifts/WC7.cs index e5d31d589..8252b6c16 100644 --- a/PKHeX.Core/MysteryGifts/WC7.cs +++ b/PKHeX.Core/MysteryGifts/WC7.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; namespace PKHeX.Core { @@ -40,8 +39,8 @@ public override int CardID public override string CardTitle { // Max len 36 char, followed by null terminator - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 2, 72)); - set => Encoding.Unicode.GetBytes(value.PadRight(36, '\0')).CopyTo(Data, 2); + get => StringConverter.GetString7(Data, 2, 0x4A); + set => StringConverter.SetString7(value, 36, 37).CopyTo(Data, 2); } internal uint RawDate @@ -183,8 +182,8 @@ public override int HeldItem public string Nickname { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x86, 0x1A)); - set => Encoding.Unicode.GetBytes(value.PadRight(12 + 1, '\0')).CopyTo(Data, 0x86); + get => StringConverter.GetString7(Data, 0x86, 0x1A); + set => StringConverter.SetString7(value, 12, 13).CopyTo(Data, 0x86); } public int Nature { get => (sbyte)Data[0xA0]; set => Data[0xA0] = (byte)value; } @@ -213,8 +212,8 @@ public string Nickname public override string OT_Name { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0xB6, 0x1A)); - set => Encoding.Unicode.GetBytes(value.PadRight(value.Length + 1, '\0')).CopyTo(Data, 0xB6); + get => StringConverter.GetString7(Data, 0xB6, 0x1A); + set => StringConverter.SetString7(value, 12, 13).CopyTo(Data, 0xB6); } public override int Level { get => Data[0xD0]; set => Data[0xD0] = (byte)value; } diff --git a/PKHeX.Core/MysteryGifts/WC8.cs b/PKHeX.Core/MysteryGifts/WC8.cs index 9c2da7cb8..589e5fdf0 100644 --- a/PKHeX.Core/MysteryGifts/WC8.cs +++ b/PKHeX.Core/MysteryGifts/WC8.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using static PKHeX.Core.RibbonIndex; namespace PKHeX.Core @@ -290,11 +289,11 @@ public override IReadOnlyList Relearn public bool IsNicknamed => false; public int Language => 2; - public string GetNickname(int language) => Util.TrimFromZero(Encoding.Unicode.GetString(Data, GetNicknameOffset(language), 0x1A)); - public void SetNickname(int language, string value) => Encoding.Unicode.GetBytes(value.PadRight(0x1A / 2, '\0')).CopyTo(Data, GetNicknameOffset(language)); + public string GetNickname(int language) => StringConverter.GetString7(Data, GetNicknameOffset(language), 0x1A); + public void SetNickname(int language, string value) => StringConverter.SetString7b(value, 12, 13).CopyTo(Data, GetNicknameOffset(language)); - public string GetOT(int language) => Util.TrimFromZero(Encoding.Unicode.GetString(Data, GetOTOffset(language), 0x1A)); - public void SetOT(int language, string value) => Encoding.Unicode.GetBytes(value.PadRight(0x1A / 2, '\0')).CopyTo(Data, GetOTOffset(language)); + public string GetOT(int language) => StringConverter.GetString7(Data, GetOTOffset(language), 0x1A); + public void SetOT(int language, string value) => StringConverter.SetString7b(value, 12, 13).CopyTo(Data, GetOTOffset(language)); private static int GetNicknameOffset(int language) { diff --git a/PKHeX.Core/MysteryGifts/WR7.cs b/PKHeX.Core/MysteryGifts/WR7.cs index bfbbc71f8..0fc079365 100644 --- a/PKHeX.Core/MysteryGifts/WR7.cs +++ b/PKHeX.Core/MysteryGifts/WR7.cs @@ -1,5 +1,4 @@ using System; -using System.Text; namespace PKHeX.Core { @@ -85,8 +84,8 @@ public override int Species public override string OT_Name { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x120, 0x1A)); - set => Encoding.Unicode.GetBytes(value.PadRight(value.Length + 1, '\0')).CopyTo(Data, 0x120 + 0xB6); // careful with length + get => StringConverter.GetString7(Data, 0x120, 0x1A); + set => StringConverter.SetString7b(value, 12, 13).CopyTo(Data, 0x120 + 0xB6); // careful with length } public LanguageID LanguageReceived diff --git a/PKHeX.Core/PKM/Strings/StringConverter.cs b/PKHeX.Core/PKM/Strings/StringConverter.cs index 56d01717c..48119fbfa 100644 --- a/PKHeX.Core/PKM/Strings/StringConverter.cs +++ b/PKHeX.Core/PKM/Strings/StringConverter.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Text; @@ -70,7 +71,11 @@ public static byte[] SetString(string value, int generation, bool jp, bool isBig /// Decoded string. public static string GetString5(byte[] data, int offset, int count) { - return SanitizeString(Util.TrimFromFFFF(Encoding.Unicode.GetString(data, offset, count))); + var raw = Encoding.Unicode.GetString(data, offset, count); + var sb = new StringBuilder(raw); + Util.TrimFromFFFF(sb); + SanitizeString(sb); + return sb.ToString(); } /// Gets the bytes for a Generation 5 string. @@ -81,12 +86,19 @@ public static string GetString5(byte[] data, int offset, int count) /// Encoded data. public static byte[] SetString5(string value, int maxLength, int padTo = 0, ushort padWith = 0) { - if (value.Length > maxLength) - value = value.Substring(0, maxLength); // Hard cap - string temp = UnSanitizeString(value, 5) - .PadRight(value.Length + 1, (char)0xFFFF) // Null Terminator - .PadRight(padTo, (char)padWith); // Padding - return Encoding.Unicode.GetBytes(temp); + var sb = new StringBuilder(value, Math.Max(maxLength, padTo)); + var delta = sb.Length - maxLength; + if (delta > 0) + sb.Remove(maxLength, delta); + + // Replace Special Characters and add Terminator + UnSanitizeString(sb, 5); + sb.Append((char)0xFFFF); + var d2 = padTo - sb.Length; + if (d2 > 0) + sb.Append((char)padWith, d2); + + return Encoding.Unicode.GetBytes(sb.ToString()); } /// Converts Generation 6 encoded data to decoded string. @@ -96,7 +108,11 @@ public static byte[] SetString5(string value, int maxLength, int padTo = 0, usho /// Decoded string. public static string GetString6(byte[] data, int offset, int count) { - return SanitizeString(Util.TrimFromZero(Encoding.Unicode.GetString(data, offset, count))); + var raw = Encoding.Unicode.GetString(data, offset, count); + var sb = new StringBuilder(raw); + Util.TrimFromZero(sb); + SanitizeString(sb); + return sb.ToString(); } /// Gets the bytes for a Generation 6 string. @@ -107,12 +123,19 @@ public static string GetString6(byte[] data, int offset, int count) /// Encoded data. public static byte[] SetString6(string value, int maxLength, int padTo = 0, ushort padWith = 0) { - if (value.Length > maxLength) - value = value.Substring(0, maxLength); // Hard cap - string temp = UnSanitizeString(value, 6) - .PadRight(value.Length + 1, '\0') // Null Terminator - .PadRight(padTo, (char)padWith); - return Encoding.Unicode.GetBytes(temp); + var sb = new StringBuilder(value); + var delta = sb.Length - maxLength; + if (delta > 0) + sb.Remove(maxLength, delta); + + // Replace Special Characters and add Terminator + UnSanitizeString(sb, 6); + sb.Append((char)0); + var d2 = padTo - sb.Length; + if (d2 > 0) + sb.Append((char)padWith, d2); + + return Encoding.Unicode.GetBytes(sb.ToString()); } /// Converts Generation 7 encoded data to decoded string. @@ -122,7 +145,12 @@ public static byte[] SetString6(string value, int maxLength, int padTo = 0, usho /// Decoded string. public static string GetString7(byte[] data, int offset, int count) { - return ConvertBin2StringG7_zh(SanitizeString(Util.TrimFromZero(Encoding.Unicode.GetString(data, offset, count)))); + var raw = Encoding.Unicode.GetString(data, offset, count); + var sb = new StringBuilder(raw); + Util.TrimFromZero(sb); + SanitizeString(sb); + RemapChineseGlyphsBin2String(sb); + return sb.ToString(); } /// Gets the bytes for a Generation 7 string. @@ -135,14 +163,21 @@ public static string GetString7(byte[] data, int offset, int count) /// Encoded data. public static byte[] SetString7(string value, int maxLength, int language, int padTo = 0, ushort padWith = 0, bool chinese = false) { + var sb = new StringBuilder(value); + var delta = sb.Length - maxLength; + if (delta > 0) + sb.Remove(maxLength, delta); if (chinese) - value = ConvertString2BinG7_zh(value, language); - if (value.Length > maxLength) - value = value.Substring(0, 12); // Hard cap - string temp = UnSanitizeString(value, 7) - .PadRight(value.Length + 1, '\0') // Null Terminator - .PadRight(padTo, (char)padWith); - return Encoding.Unicode.GetBytes(temp); + ConvertString2BinG7_zh(sb, language); + + // Replace Special Characters and add Terminator + UnSanitizeString(sb, 7); + sb.Append((char)0); + var d2 = padTo - sb.Length; + if (d2 > 0) + sb.Append((char)padWith, d2); + + return Encoding.Unicode.GetBytes(sb.ToString()); } /// Gets the bytes for a Generation 7 string. @@ -155,34 +190,43 @@ public static byte[] SetString7(string value, int maxLength, int language, int p /// Encoded data. public static byte[] SetString7b(string value, int maxLength, int language, int padTo = 0, ushort padWith = 0, bool chinese = false) { + var sb = new StringBuilder(value); + var delta = sb.Length - maxLength; + if (delta > 0) + sb.Remove(maxLength, delta); if (chinese) - value = ConvertString2BinG7_zh(value, language); - if (value.Length > maxLength) - value = value.Substring(0, 12); // Hard cap - string temp = UnSanitizeString7b(value) - .PadRight(value.Length + 1, '\0') // Null Terminator - .PadRight(padTo, (char)padWith); - return Encoding.Unicode.GetBytes(temp); + ConvertString2BinG7_zh(sb, language); + + // Replace Special Characters and add Terminator + UnSanitizeString7b(sb); + sb.Append((char)0); + var d2 = padTo - sb.Length; + if (d2 > 0) + sb.Append((char)padWith, d2); + + return Encoding.Unicode.GetBytes(sb.ToString()); } /// /// Converts a Unicode string to Generation 7 in-game Chinese string. /// - /// Unicode string. + /// Unicode string. /// Detection of language for Traditional Chinese check /// In-game Chinese string. - private static string ConvertString2BinG7_zh(string input, int lang) + private static void ConvertString2BinG7_zh(StringBuilder sb, int lang) { - var str = new StringBuilder(); - // A string cannot contain a mix of CHS and CHT characters. + var input = sb.ToString(); bool traditional = input.Any(chr => G7_CHT.ContainsKey(chr) && !G7_CHS.ContainsKey(chr)) || (lang == 10 && !input.Any(chr => G7_CHT.ContainsKey(chr) ^ G7_CHS.ContainsKey(chr))); // CHS and CHT have the same display name var table = traditional ? G7_CHT : G7_CHS; - foreach (char chr in input) - str.Append(table.TryGetValue(chr, out int index) ? (char)(index + Gen7_ZH_Ofs) : chr); - return str.ToString(); + for (int i = 0; i < sb.Length; i++) + { + var chr = sb[i]; + if (table.TryGetValue(chr, out var index)) + sb[i] = (char) (index + Gen7_ZH_Ofs); + } } /// @@ -190,24 +234,15 @@ private static string ConvertString2BinG7_zh(string input, int lang) /// /// In-game Chinese string. /// Unicode string. - private static string ConvertBin2StringG7_zh(string input) + private static void RemapChineseGlyphsBin2String(StringBuilder input) { - var str = new StringBuilder(); - foreach (var val in input) - str.Append((char)GetGen7ChineseChar(val)); - return str.ToString(); - } - - /// - /// Shifts a character from the Chinese character tables - /// - /// Input value to shift - /// Shifted character - private static ushort GetGen7ChineseChar(ushort val) - { - if (Gen7_ZH_Ofs <= val && val < Gen7_ZH_Ofs + Gen7_ZH.Length) - return Gen7_ZH[val - Gen7_ZH_Ofs]; - return val; // regular character + for (int i = 0; i < input.Length; i++) + { + char val = input[i]; + if (val < Gen7_ZH_Ofs || val >= Gen7_ZH_Ofs + Gen7_ZH.Length) + continue; + input[i] = Gen7_ZH[val - Gen7_ZH_Ofs]; + } } #region Gen 7 Chinese Character Tables @@ -231,19 +266,19 @@ private static ushort GetGen7ChineseChar(ushort val) /// /// Converts full width to single width /// - /// Input string to sanitize. + /// Input string to sanitize. /// - internal static string SanitizeString(string str) + internal static void SanitizeString(StringBuilder s) { - if (str.Length == 0) - return str; - var s = str.Replace('’', '\''); // Farfetch'd + if (s.Length == 0) + return; + s.Replace('’', '\''); // Farfetch'd // remap custom glyphs to unicode - s = s.Replace('\uE08F', '♀'); // ♀ (gen6+) - s = s.Replace('\uE08E', '♂'); // ♂ (gen6+) - s = s.Replace('\u246E', '♀'); // ♀ (gen5) - return s.Replace('\u246D', '♂'); // ♂ (gen5) + s.Replace('\uE08F', '♀'); // ♀ (gen6+) + s.Replace('\uE08E', '♂'); // ♂ (gen6+) + s.Replace('\u246E', '♀'); // ♀ (gen5) + s.Replace('\u246D', '♂'); // ♂ (gen5) } /// @@ -251,10 +286,10 @@ internal static string SanitizeString(string str) /// /// Input string to set. /// - private static string UnSanitizeString7b(string str) + private static void UnSanitizeString7b(StringBuilder str) { // gender chars always full width - return str.Replace('\'', '’'); // Farfetch'd + str.Replace('\'', '’'); // Farfetch'd } /// @@ -263,28 +298,28 @@ private static string UnSanitizeString7b(string str) /// Input string to set. /// Generation specific context /// - internal static string UnSanitizeString(string str, int generation) + internal static void UnSanitizeString(StringBuilder str, int generation) { - var s = str; if (generation >= 6) - s = str.Replace('\'', '’'); // Farfetch'd + str.Replace('\'', '’'); // Farfetch'd if (generation <= 5) { - s = s.Replace('\u2640', '\u246E'); // ♀ - return s.Replace('\u2642', '\u246D'); // ♂ + str.Replace('\u2640', '\u246E'); // ♀ + str.Replace('\u2642', '\u246D'); // ♂ + return; } - var context = str.Except(FullToHalf); + var context = str.ToString().Except(FullToHalf); bool fullwidth = context.Select(c => c >> 12) // select the group the char belongs to .Any(c => c is not (0 or 0xE) /* Latin, Special Symbols */); if (fullwidth) // jp/ko/zh strings - return s; // keep as full width + return; // keep as full width // Convert back to half width glyphs - s = s.Replace('\u2640', '\uE08F'); // ♀ - return s.Replace('\u2642', '\uE08E'); // ♂ + str.Replace('\u2640', '\uE08F'); // ♀ + str.Replace('\u2642', '\uE08E'); // ♂ } private static readonly char[] FullToHalf = {'\u2640', '\u2642'}; // ♀♂ diff --git a/PKHeX.Core/PKM/Strings/StringConverter12.cs b/PKHeX.Core/PKM/Strings/StringConverter12.cs index b629d07e3..aa2920320 100644 --- a/PKHeX.Core/PKM/Strings/StringConverter12.cs +++ b/PKHeX.Core/PKM/Strings/StringConverter12.cs @@ -84,7 +84,8 @@ public static string GetString1(byte[] data, int offset, int count, bool jp) break; s.Append(c); } - return StringConverter.SanitizeString(s.ToString()); + StringConverter.SanitizeString(s); + return s.ToString(); } /// diff --git a/PKHeX.Core/PKM/Strings/StringConverter2KOR.cs b/PKHeX.Core/PKM/Strings/StringConverter2KOR.cs index 8495569be..1257bd461 100644 --- a/PKHeX.Core/PKM/Strings/StringConverter2KOR.cs +++ b/PKHeX.Core/PKM/Strings/StringConverter2KOR.cs @@ -35,7 +35,8 @@ public static string GetString2KOR(byte[] data, int offset, int count) break; s.Append(c); } - return StringConverter.SanitizeString(s.ToString()); + StringConverter.SanitizeString(s); + return s.ToString(); } /// diff --git a/PKHeX.Core/PKM/Strings/StringConverter3.cs b/PKHeX.Core/PKM/Strings/StringConverter3.cs index 96f8fb9e4..0c181282b 100644 --- a/PKHeX.Core/PKM/Strings/StringConverter3.cs +++ b/PKHeX.Core/PKM/Strings/StringConverter3.cs @@ -27,7 +27,8 @@ public static string GetString3(byte[] data, int offset, int count, bool jp) break; s.Append(c); } - return StringConverter.SanitizeString(s.ToString()); + StringConverter.SanitizeString(s); + return s.ToString(); } /// @@ -76,7 +77,10 @@ public static byte[] SetString3(string value, int maxLength, bool jp, int padTo /// Decoded string. public static string GetBEString3(byte[] data, int offset, int count) { - return Util.TrimFromZero(Encoding.BigEndianUnicode.GetString(data, offset, count)); + var raw = Encoding.BigEndianUnicode.GetString(data, offset, count); + var sb = new StringBuilder(raw); + Util.TrimFromZero(sb); + return sb.ToString(); } /// Gets the bytes for a Big Endian string. @@ -89,10 +93,14 @@ public static byte[] SetBEString3(string value, int maxLength, int padTo = 0, us { if (value.Length > maxLength) value = value.Substring(0, maxLength); // Hard cap - var temp = StringConverter.SanitizeString(value) - .PadRight(value.Length + 1, (char)0) // Null Terminator - .PadRight(padTo, (char)padWith); - return Encoding.BigEndianUnicode.GetBytes(temp); + var sb = new StringBuilder(value); + StringConverter.SanitizeString(sb); + sb.Append('\0'); + var delta = padTo - value.Length; + if (delta > 0) + sb.Append((char)padWith, delta); + var result = sb.ToString(); + return Encoding.BigEndianUnicode.GetBytes(result); } /// diff --git a/PKHeX.Core/PKM/Strings/StringConverter4.cs b/PKHeX.Core/PKM/Strings/StringConverter4.cs index 45e2ec2d9..618c70e69 100644 --- a/PKHeX.Core/PKM/Strings/StringConverter4.cs +++ b/PKHeX.Core/PKM/Strings/StringConverter4.cs @@ -28,7 +28,8 @@ public static string GetString4(byte[] data, int offset, int count) break; s.Append((char)chr); } - return StringConverter.SanitizeString(s.ToString()); + StringConverter.SanitizeString(s); + return s.ToString(); } /// Gets the bytes for a 4th Generation String @@ -39,16 +40,22 @@ public static string GetString4(byte[] data, int offset, int count) /// Encoded data. public static byte[] SetString4(string value, int maxLength, int padTo = 0, ushort padWith = 0) { - if (value.Length > maxLength) - value = value.Substring(0, maxLength); // Hard cap - var temp = StringConverter.UnSanitizeString(value, 4) // Replace Special Characters and add Terminator - .PadRight(value.Length + 1, (char)0xFFFF) // Null Terminator - .PadRight(padTo, (char)padWith); // Padding + var sb = new StringBuilder(value); + var delta = sb.Length - maxLength; + if (delta > 0) + sb.Remove(maxLength, delta); - var data = new byte[temp.Length * 2]; - for (int i = 0; i < temp.Length; i++) + // Replace Special Characters and add Terminator + StringConverter.UnSanitizeString(sb, 4); + sb.Append((char)0xFFFF); + var d2 = padTo - sb.Length; + if (d2 > 0) + sb.Append((char)padWith, d2); + + var data = new byte[sb.Length * 2]; + for (int i = 0; i < sb.Length; i++) { - var chr = temp[i]; + var chr = sb[i]; var val = ConvertChar2ValueG4(chr); BitConverter.GetBytes(val).CopyTo(data, i * 2); } @@ -75,7 +82,8 @@ public static string GetBEString4(byte[] data, int offset, int count) break; sb.Append((char)chr); } - return StringConverter.SanitizeString(sb.ToString()); + StringConverter.SanitizeString(sb); + return sb.ToString(); } /// @@ -88,17 +96,22 @@ public static string GetBEString4(byte[] data, int offset, int count) /// Byte array containing encoded character data public static byte[] SetBEString4(string value, int maxLength, int padTo = 0, ushort padWith = 0) { - if (value.Length > maxLength) - value = value.Substring(0, maxLength); // Hard cap + var sb = new StringBuilder(value); + var delta = sb.Length - maxLength; + if (delta > 0) + sb.Remove(maxLength, delta); - var temp = StringConverter.UnSanitizeString(value, 4) // Replace Special Characters and add Terminator - .PadRight(value.Length + 1, (char)0xFFFF) // Null Terminator - .PadRight(padTo, (char)padWith); // Padding + // Replace Special Characters and add Terminator + StringConverter.UnSanitizeString(sb, 4); + sb.Append((char)0xFFFF); + var d2 = padTo - sb.Length; + if (d2 > 0) + sb.Append((char)padWith, d2); - var data = new byte[temp.Length * 2]; - for (int i = 0; i < temp.Length; i++) + var data = new byte[sb.Length * 2]; + for (int i = 0; i < sb.Length; i++) { - var chr = temp[i]; + var chr = sb[i]; var val = ConvertChar2ValueG4(chr); BigEndian.GetBytes(val).CopyTo(data, i * 2); } diff --git a/PKHeX.Core/Saves/SAV3GCMemoryCard.cs b/PKHeX.Core/Saves/SAV3GCMemoryCard.cs index 3a34a28c3..6db89917b 100644 --- a/PKHeX.Core/Saves/SAV3GCMemoryCard.cs +++ b/PKHeX.Core/Saves/SAV3GCMemoryCard.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; namespace PKHeX.Core diff --git a/PKHeX.Core/Saves/SAV4BR.cs b/PKHeX.Core/Saves/SAV4BR.cs index 6549cdfe7..eb1ddb6c6 100644 --- a/PKHeX.Core/Saves/SAV4BR.cs +++ b/PKHeX.Core/Saves/SAV4BR.cs @@ -153,8 +153,7 @@ public static bool IsChecksumsValid(byte[] sav) private string GetOTName(int slot) { var ofs = 0x390 + (0x6FF00 * slot); - var str = Encoding.BigEndianUnicode.GetString(Data, ofs, 0x10); - return Util.TrimFromZero(str); + return StringConverter4.GetBEString4(Data, ofs, 0x10); } private void SetOTName(int slot, string name) @@ -181,8 +180,8 @@ public override string GetBoxName(int box) if (BoxName < 0) return $"BOX {box + 1}"; - var str = Encoding.BigEndianUnicode.GetString(Data, BoxName + (box * BoxNameLength), BoxNameLength); - str = Util.TrimFromZero(str); + int ofs = BoxName + (box * BoxNameLength); + var str = GetString(ofs, BoxNameLength); if (string.IsNullOrWhiteSpace(str)) return $"BOX {box + 1}"; return str; @@ -194,12 +193,11 @@ public override void SetBoxName(int box, string value) return; int ofs = BoxName + (box * BoxNameLength); - var str = Encoding.BigEndianUnicode.GetString(Data, ofs, BoxNameLength); - str = Util.TrimFromZero(str); + var str = GetString(ofs, BoxNameLength); if (string.IsNullOrWhiteSpace(str)) return; - var data = Encoding.BigEndianUnicode.GetBytes(value.PadLeft(BoxNameLength / 2, '\0')); + var data = SetString(value, BoxNameLength / 2, BoxNameLength / 2); SetData(data, ofs); } diff --git a/PKHeX.Core/Saves/SAV6AO.cs b/PKHeX.Core/Saves/SAV6AO.cs index 5088bd96d..5513262a1 100644 --- a/PKHeX.Core/Saves/SAV6AO.cs +++ b/PKHeX.Core/Saves/SAV6AO.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; namespace PKHeX.Core { @@ -179,7 +178,7 @@ public override void SetDaycareHasEgg(int loc, bool hasEgg) Data[ofs + 0x1E0] = hasEgg ? 1 : 0; } - public override string JPEGTitle => HasJPPEGData ? string.Empty : Util.TrimFromZero(Encoding.Unicode.GetString(Data, JPEG, 0x1A)); + public override string JPEGTitle => HasJPPEGData ? string.Empty : StringConverter.GetString6(Data, JPEG, 0x1A); public override byte[] GetJPEGData() => HasJPPEGData ? Array.Empty() : GetData(JPEG + 0x54, 0xE004); private bool HasJPPEGData => Data[JPEG + 0x54] == 0xFF; diff --git a/PKHeX.Core/Saves/SAV6XY.cs b/PKHeX.Core/Saves/SAV6XY.cs index fd98cc1da..d64f11531 100644 --- a/PKHeX.Core/Saves/SAV6XY.cs +++ b/PKHeX.Core/Saves/SAV6XY.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; namespace PKHeX.Core { @@ -117,7 +116,7 @@ public override void SetDaycareRNGSeed(int loc, string seed) Util.GetBytesFromHexString(seed).CopyTo(Data, DaycareOffset + 0x1E8); } - public override string JPEGTitle => HasJPPEGData ? string.Empty : Util.TrimFromZero(Encoding.Unicode.GetString(Data, JPEG, 0x1A)); + public override string JPEGTitle => HasJPPEGData ? string.Empty : StringConverter.GetString6(Data, JPEG, 0x1A); public override byte[] GetJPEGData() => HasJPPEGData ? Array.Empty() : GetData(JPEG + 0x54, 0xE004); private bool HasJPPEGData => Data[JPEG + 0x54] == 0xFF; diff --git a/PKHeX.Core/Saves/Storage/SAV4Ranch.cs b/PKHeX.Core/Saves/Storage/SAV4Ranch.cs index 5d91ec61c..57a1cfa9d 100644 --- a/PKHeX.Core/Saves/Storage/SAV4Ranch.cs +++ b/PKHeX.Core/Saves/Storage/SAV4Ranch.cs @@ -86,7 +86,7 @@ protected override void SetChecksums() SetData(result, 0); } - public override string GetString(byte[] data, int offset, int length) => Util.TrimFromZero(Encoding.BigEndianUnicode.GetString(data, offset, length)); + public override string GetString(byte[] data, int offset, int length) => StringConverter4.GetBEString4(data, offset, length); public override byte[] SetString(string value, int maxLength, int PadToSize = 0, ushort PadWith = 0) { diff --git a/PKHeX.Core/Saves/Substructures/Battle Videos/BV6.cs b/PKHeX.Core/Saves/Substructures/Battle Videos/BV6.cs index 798c97ae4..73ce1a7cb 100644 --- a/PKHeX.Core/Saves/Substructures/Battle Videos/BV6.cs +++ b/PKHeX.Core/Saves/Substructures/Battle Videos/BV6.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; // ReSharper disable UnusedType.Local namespace PKHeX.Core @@ -29,14 +28,14 @@ internal new static bool IsValid(byte[] data) public string Debug1 { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x6, 24)); - set => Encoding.Unicode.GetBytes(value.PadRight(12, '\0')).CopyTo(Data, 0x6); + get => StringConverter.GetString6(Data, 0x6, 0x1A); + set => StringConverter.SetString6(value, 12, 13).CopyTo(Data, 0x6); } public string Debug2 { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x50, 24)); - set => Encoding.Unicode.GetBytes(value.PadRight(12, '\0')).CopyTo(Data, 0x50); + get => StringConverter.GetString6(Data, 0x50, 0x1A); + set => StringConverter.SetString6(value, 12, 13).CopyTo(Data, 0x50); } public ulong RNGConst1 { get => BitConverter.ToUInt64(Data, 0x1A0); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1A0); } @@ -54,9 +53,8 @@ public string[] GetPlayerNames() string[] trainers = new string[PlayerCount]; for (int i = 0; i < PlayerCount; i++) { - trainers[i] = Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0xEC + (0x1A * i), 0x1A)); - if (string.IsNullOrWhiteSpace(trainers[i])) - trainers[i] = NPC; + var str = StringConverter.GetString6(Data, 0xEC + (0x1A * i), 0x1A); + trainers[i] = string.IsNullOrWhiteSpace(str) ? NPC : str; } return trainers; } @@ -69,7 +67,7 @@ public void SetPlayerNames(IReadOnlyList value) for (int i = 0; i < PlayerCount; i++) { string tr = value[i] == NPC ? string.Empty : value[i]; - Encoding.Unicode.GetBytes(tr.PadRight(0x1A / 2)).CopyTo(Data, 0xEC + (0x1A * i)); + StringConverter.SetString6(tr, 12, 13).CopyTo(Data, 0xEC + (0x1A * i)); } } diff --git a/PKHeX.Core/Saves/Substructures/Battle Videos/BV7.cs b/PKHeX.Core/Saves/Substructures/Battle Videos/BV7.cs index 29b2a4008..f3f37f5be 100644 --- a/PKHeX.Core/Saves/Substructures/Battle Videos/BV7.cs +++ b/PKHeX.Core/Saves/Substructures/Battle Videos/BV7.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; namespace PKHeX.Core { @@ -65,9 +64,8 @@ public string[] GetPlayerNames() string[] trainers = new string[PlayerCount]; for (int i = 0; i < PlayerCount; i++) { - trainers[i] = Util.TrimFromZero(Encoding.Unicode.GetString(Data, 0x12C + (0x1A * i), 0x1A)); - if (string.IsNullOrWhiteSpace(trainers[i])) - trainers[i] = NPC; + var str = StringConverter.GetString7(Data, 0x12C + (0x1A * i), 0x1A); + trainers[i] = string.IsNullOrWhiteSpace(trainers[i]) ? NPC : str; } return trainers; } @@ -80,7 +78,7 @@ public void SetPlayerNames(IReadOnlyList value) for (int i = 0; i < PlayerCount; i++) { string tr = value[i] == NPC ? string.Empty : value[i]; - Encoding.Unicode.GetBytes(tr.PadRight(0x1A / 2)).CopyTo(Data, 0xEC + (0x1A * i)); + StringConverter.SetString7(tr, 12, 13).CopyTo(Data, 0xEC + (0x1A * i)); } } diff --git a/PKHeX.Core/Saves/Substructures/Gen6/PSS6.cs b/PKHeX.Core/Saves/Substructures/Gen6/PSS6.cs index 49e59302c..f5bbb8c10 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/PSS6.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/PSS6.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; namespace PKHeX.Core { @@ -48,8 +47,8 @@ private static bool ReadTrainer(ICollection result, byte[] Data, int ofs if (pssID == 0) return false; // no data - string otname = Util.TrimFromZero(Encoding.Unicode.GetString(Data, ofs + 8, 0x1A)); - string message = Util.TrimFromZero(Encoding.Unicode.GetString(Data, ofs + 0x22, 0x22)); + string otname = StringConverter.GetString6(Data, ofs + 8, 0x1A); + string message = StringConverter.GetString6(Data, ofs + 8 + 0x1A, 0x22); // Trim terminated diff --git a/PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs b/PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs index e9455648e..0013f4e25 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs @@ -1,5 +1,4 @@ using System; -using System.Text; namespace PKHeX.Core { @@ -34,14 +33,8 @@ public int TotalFestaCoins public string FestivalPlazaName { - get => Util.TrimFromZero(Encoding.Unicode.GetString(Data, Offset + 0x510, 0x2A)); - set - { - const int max = 20; - if (value.Length > max) - value = value.Substring(0, max); - Encoding.Unicode.GetBytes(value.PadRight(value.Length + 1, '\0')).CopyTo(Data, Offset + 0x510); - } + get => StringConverter.GetString7(Data, Offset + 0x510, 0x2A); + set => StringConverter.SetString7(value, 20, 21).CopyTo(Data, Offset + 0x510); } public ushort FestaRank { get => BitConverter.ToUInt16(Data, Offset + 0x53A); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x53A); } diff --git a/PKHeX.Core/Util/Util.cs b/PKHeX.Core/Util/Util.cs index f22064d28..172f43a84 100644 --- a/PKHeX.Core/Util/Util.cs +++ b/PKHeX.Core/Util/Util.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; +using System.Text; namespace PKHeX.Core { @@ -51,8 +52,7 @@ public static uint ToUInt32(string value) if (!IsNum(c)) continue; result *= 10; - result += c; - result -= '0'; + result += (uint)(c - '0'); } return result; } @@ -158,7 +158,7 @@ public static string GetHexStringFromBytes(byte[] data, int offset, int length) /// /// String to trim. /// Trimmed string. - public static string TrimFromFFFF(string input) => TrimFromFirst(input, (char)0xFFFF); + public static void TrimFromFFFF(StringBuilder input) => TrimFromFirst(input, (char)0xFFFF); /// /// Trims a string at the first instance of a 0x0000 terminator. @@ -167,6 +167,13 @@ public static string GetHexStringFromBytes(byte[] data, int offset, int length) /// Trimmed string. public static string TrimFromZero(string input) => TrimFromFirst(input, '\0'); + /// + /// Trims a string at the first instance of a 0x0000 terminator. + /// + /// String to trim. + /// Trimmed string. + public static void TrimFromZero(StringBuilder input) => TrimFromFirst(input, '\0'); + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static string TrimFromFirst(string input, char c) { @@ -174,6 +181,16 @@ private static string TrimFromFirst(string input, char c) return index < 0 ? input : input.Substring(0, index); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void TrimFromFirst(StringBuilder input, char c) + { + for (int i = 0; i < input.Length; i++) + { + if (input[i] == c) + input.Remove(i, input.Length - i); + } + } + public static Dictionary[] GetMultiDictionary(IReadOnlyList> nameArray) { var result = new Dictionary[nameArray.Count]; diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs index 614e65ecd..ec9d4c67f 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs @@ -152,8 +152,8 @@ private void AddEntryDescription(int offset, List s, int species) uint shiny = slgf >> 14 & 0x1; // uint unkn = slgf >> 15; - string nickname = Util.TrimFromZero(Encoding.Unicode.GetString(data, offset + 0x18, 24)); - string OTname = Util.TrimFromZero(Encoding.Unicode.GetString(data, offset + 0x30, 24)); + string nickname = StringConverter.GetString6(data, offset + 0x18, 24); + string OTname = StringConverter.GetString6(data, offset + 0x30, 24); string genderstr = gendersymbols[(int)gender]; string shinystr = shiny == 1 ? "Yes" : "No"; @@ -200,8 +200,8 @@ private void NUP_PartyIndex_ValueChanged(object sender, EventArgs e) TB_TID.Text = BitConverter.ToUInt16(data, offset + 0x10).ToString("00000"); TB_SID.Text = BitConverter.ToUInt16(data, offset + 0x12).ToString("00000"); - TB_Nickname.Text = Util.TrimFromZero(Encoding.Unicode.GetString(data, offset + 0x18, 24)); - TB_OT.Text = Util.TrimFromZero(Encoding.Unicode.GetString(data, offset + 0x30, 24)); + TB_Nickname.Text = StringConverter.GetString6(data, offset + 0x18, 24); + TB_OT.Text = StringConverter.GetString6(data, offset + 0x30, 24); uint slgf = BitConverter.ToUInt32(data, offset + 0x14); uint form = slgf & 0x1F; @@ -427,8 +427,7 @@ private void ChangeNickname(object sender, MouseEventArgs e) tb.Text = d.FinalString; d.FinalBytes.CopyTo(data, offset + 0x18); - string nickname = Util.TrimFromZero(Encoding.Unicode.GetString(data, offset + 0x18, 24)); - TB_Nickname.Text = nickname; + TB_Nickname.Text = StringConverter.GetString6(data, offset + 0x18, 24); } } } diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_SecretBase.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_SecretBase.cs index cf5530aed..65353ed56 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_SecretBase.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_SecretBase.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Linq; -using System.Text; using System.Windows.Forms; using PKHeX.Core; @@ -73,11 +72,11 @@ private void PopFavorite() int playeroff = SAV.SecretBase + 0x326; int favoff = SAV.SecretBase + 0x63A; - string OT = Util.TrimFromZero(Encoding.Unicode.GetString(SAV.Data, playeroff + 0x218, 0x1A)); + string OT = StringConverter.GetString6(SAV.Data, playeroff + 0x218, 0x1A); LB_Favorite.Items.Add($"* {OT}"); for (int i = 0; i < 30; i++) { - string BaseTrainer = Util.TrimFromZero(Encoding.Unicode.GetString(SAV.Data, favoff + (i * 0x3E0) + 0x218, 0x1A)); + string BaseTrainer = StringConverter.GetString6(SAV.Data, favoff + (i * 0x3E0) + 0x218, 0x1A); if (BaseTrainer.Length < 1 || BaseTrainer[0] == '\0') BaseTrainer = "Empty"; LB_Favorite.Items.Add($"{i} {BaseTrainer}"); @@ -520,7 +519,7 @@ private void B_FDelete_Click(object sender, EventArgs e) int index = LB_Favorite.SelectedIndex - 1; int favoff = SAV.SecretBase + 0x63A; - string BaseTrainer = Util.TrimFromZero(Encoding.Unicode.GetString(SAV.Data, favoff + (index * 0x3E0) + 0x218, 0x1A)); + string BaseTrainer = StringConverter.GetString6(SAV.Data, favoff + (index * 0x3E0) + 0x218, 0x1A); if (string.IsNullOrEmpty(BaseTrainer)) BaseTrainer = "Empty";