using System; namespace PKHeX.Core; /// /// Mainline format for Generation 1 & 2 objects. /// /// This format stores and in buffers separate from the rest of the details. public abstract class GBPKML : GBPKM { internal const int StringLengthJapanese = 6; internal const int StringLengthNotJapan = 11; public sealed override int MaxStringLengthOT => Japanese ? 5 : 7; public sealed override int MaxStringLengthNickname => Japanese ? 5 : 10; public sealed override bool Japanese => RawOT.Length == StringLengthJapanese; private readonly byte[] RawOT; private readonly byte[] RawNickname; // Trash Bytes public sealed override Span Nickname_Trash => RawNickname; public sealed override Span OT_Trash => RawOT; protected GBPKML(int size, bool jp = false) : base(size) { int strLen = jp ? StringLengthJapanese : StringLengthNotJapan; // initialize string buffers RawOT = new byte[strLen]; RawNickname = new byte[strLen]; OT_Trash.Fill(StringConverter12.G1TerminatorCode); Nickname_Trash.Fill(StringConverter12.G1TerminatorCode); } protected GBPKML(byte[] data, bool jp = false) : base(data) { int strLen = jp ? StringLengthJapanese : StringLengthNotJapan; // initialize string buffers RawOT = new byte[strLen]; RawNickname = new byte[strLen]; OT_Trash.Fill(StringConverter12.G1TerminatorCode); Nickname_Trash.Fill(StringConverter12.G1TerminatorCode); } public override void SetNotNicknamed(int language) => GetNonNickname(language, RawNickname); protected override void GetNonNickname(int language, Span data) { var name = SpeciesName.GetSpeciesNameGeneration(Species, language, Format); SetString(name, data, data.Length, StringConverterOption.Clear50); if (Korean) return; // Decimal point<->period fix foreach (ref var c in data) { if (c == 0xF2) c = 0xE8; } } private string GetString(ReadOnlySpan span) { if (Korean) return StringConverter2KOR.GetString(span); return StringConverter12.GetString(span, Japanese); } private int SetString(ReadOnlySpan value, Span destBuffer, int maxLength, StringConverterOption option = StringConverterOption.None) { if (Korean) return StringConverter2KOR.SetString(destBuffer, value, maxLength, option); return StringConverter12.SetString(destBuffer, value, maxLength, Japanese, option); } public sealed override string Nickname { get => GetString(Nickname_Trash); set { if (!IsNicknamed && Nickname == value) return; SetStringKeepTerminatorStyle(value, Nickname_Trash); } } public sealed override string OT_Name { get => GetString(OT_Trash); set { if (value == OT_Name) return; SetStringKeepTerminatorStyle(value, OT_Trash); } } private void SetStringKeepTerminatorStyle(ReadOnlySpan value, Span exist) { // Reset the destination buffer based on the termination style of the existing string. bool zeroed = exist.Contains(0); StringConverterOption converterOption = (zeroed) ? StringConverterOption.ClearZero : StringConverterOption.Clear50; SetString(value, exist, value.Length, converterOption); } }