From 156abbe83c49fca67b0f6d835022d8942bcd66f4 Mon Sep 17 00:00:00 2001 From: Greg Edwards Date: Sat, 18 Apr 2015 17:19:52 -0400 Subject: [PATCH] Created base class for GTS records implementing BinarySerializableBase --- library/Library.csproj | 1 + library/Structures/GtsRecord4.cs | 159 +++++++++++----------------- library/Structures/GtsRecord5.cs | 134 ++++++++++++----------- library/Structures/GtsRecordBase.cs | 53 ++++++++++ 4 files changed, 181 insertions(+), 166 deletions(-) create mode 100644 library/Structures/GtsRecordBase.cs diff --git a/library/Library.csproj b/library/Library.csproj index b7dbc0d4..b6735d17 100644 --- a/library/Library.csproj +++ b/library/Library.csproj @@ -90,6 +90,7 @@ + diff --git a/library/Structures/GtsRecord4.cs b/library/Structures/GtsRecord4.cs index bdfdf1ab..c7ce20dd 100644 --- a/library/Structures/GtsRecord4.cs +++ b/library/Structures/GtsRecord4.cs @@ -13,19 +13,24 @@ namespace PkmnFoundations.Structures /// Includes a Pokémon box structure and metadata related to the trainer /// and request. /// - public class GtsRecord4 : IEquatable + public class GtsRecord4 : GtsRecordBase, IEquatable { - // todo: We should have a base class for Gen4/5 GTS records. - - public GtsRecord4() + public GtsRecord4() : base() { + Initialize(); } - public GtsRecord4(byte[] data) + public GtsRecord4(byte[] data) : base() { + Initialize(); Load(data); } + private void Initialize() + { + + } + /// /// Obfuscated Pokémon (pkm) data. 236 bytes /// @@ -83,66 +88,65 @@ namespace PkmnFoundations.Structures public byte TrainerVersion; public byte TrainerLanguage; - public byte[] Save() + protected override void Save(BinaryWriter writer) { // todo: enclose in properties and validate these when assigning. if (Data.Length != 0xEC) throw new FormatException("PKM length is incorrect"); if (TrainerName.RawData.Length != 0x10) throw new FormatException("Trainer name length is incorrect"); - byte[] data = new byte[292]; - MemoryStream s = new MemoryStream(data); - s.Write(Data, 0, 0xEC); - s.Write(BitConverter.GetBytes(Species), 0, 2); - s.WriteByte((byte)Gender); - s.WriteByte(Level); - s.Write(BitConverter.GetBytes(RequestedSpecies), 0, 2); - s.WriteByte((byte)RequestedGender); - s.WriteByte(RequestedMinLevel); - s.WriteByte(RequestedMaxLevel); - s.WriteByte(Unknown1); - s.WriteByte((byte)TrainerGender); - s.WriteByte(Unknown2); - s.Write(BitConverter.GetBytes(DateToTimestamp(TimeDeposited)), 0, 8); - s.Write(BitConverter.GetBytes(DateToTimestamp(TimeExchanged)), 0, 8); - s.Write(BitConverter.GetBytes(PID), 0, 4); - s.Write(TrainerName.RawData, 0, 0x10); - s.Write(BitConverter.GetBytes(TrainerOT), 0, 2); - s.WriteByte(TrainerCountry); - s.WriteByte(TrainerRegion); - s.WriteByte(TrainerClass); - s.WriteByte(IsExchanged); - s.WriteByte(TrainerVersion); - s.WriteByte(TrainerLanguage); - s.Close(); - return data; + + writer.Write(Data, 0, 0xEC); // 0x0000 + writer.Write(Species); // 0x00EC + writer.Write((byte)Gender); // 0x00EE + writer.Write(Level); // 0x00EF + writer.Write(RequestedSpecies); // 0x00F0 + writer.Write((byte)RequestedGender); // 0x00F2 + writer.Write(RequestedMinLevel); // 0x00F3 + writer.Write(RequestedMaxLevel); // 0x00F4 + writer.Write(Unknown1); // 0x00F5 + writer.Write((byte)TrainerGender); // 0x00F6 + writer.Write(Unknown2); // 0x00F7 + writer.Write(DateToTimestamp(TimeDeposited)); // 0x00F8 + writer.Write(DateToTimestamp(TimeExchanged)); // 0x0100 + writer.Write(PID); // 0x0108 + writer.Write(TrainerName.RawData, 0, 0x10); // 0x010C + writer.Write(TrainerOT); // 0x011C + writer.Write(TrainerCountry); // 0x011E + writer.Write(TrainerRegion); // 0x011F + writer.Write(TrainerClass); // 0x0120 + writer.Write(IsExchanged); // 0x0121 + writer.Write(TrainerVersion); // 0x0122 + writer.Write(TrainerLanguage); // 0x0123 } - public void Load(byte[] data) + protected override void Load(BinaryReader reader) { - if (data.Length != 292) throw new FormatException("GTS record length is incorrect."); + Data = reader.ReadBytes(0xEC); // 0x0000 + Species = reader.ReadUInt16(); // 0x00EC + Gender = (Genders)reader.ReadByte(); // 0x00EE + Level = reader.ReadByte(); // 0x00EF + RequestedSpecies = reader.ReadUInt16(); // 0x00F0 + RequestedGender = (Genders)reader.ReadByte(); // 0x00F2 + RequestedMinLevel = reader.ReadByte(); // 0x00F3 + RequestedMaxLevel = reader.ReadByte(); // 0x00F4 + Unknown1 = reader.ReadByte(); // 0x00F5 + TrainerGender = (TrainerGenders)reader.ReadByte(); // 0x00F6 + Unknown2 = reader.ReadByte(); // 0x00F7 + TimeDeposited = TimestampToDate(reader.ReadUInt64()); // 0x00F8 + TimeExchanged = TimestampToDate(reader.ReadUInt64()); // 0x0100 + PID = reader.ReadInt32(); // 0x0108 + TrainerName = new EncodedString4(reader.ReadBytes(0x10)); // 0x010C + TrainerOT = reader.ReadUInt16(); // 0x011C + TrainerCountry = reader.ReadByte(); // 0x011E + TrainerRegion = reader.ReadByte(); // 0x011F + TrainerClass = reader.ReadByte(); // 0x0120 + IsExchanged = reader.ReadByte(); // 0x0121 + TrainerVersion = reader.ReadByte(); // 0x0122 + TrainerLanguage = reader.ReadByte(); // 0x0123 + } - Data = new byte[0xEC]; - Array.Copy(data, 0, Data, 0, 0xEC); - Species = BitConverter.ToUInt16(data, 0xEC); - Gender = (Genders)data[0xEE]; - Level = data[0xEF]; - RequestedSpecies = BitConverter.ToUInt16(data, 0xF0); - RequestedGender = (Genders)data[0xF2]; - RequestedMinLevel = data[0xF3]; - RequestedMaxLevel = data[0xF4]; - Unknown1 = data[0xF5]; - TrainerGender = (TrainerGenders)data[0xF6]; - Unknown2 = data[0xF7]; - TimeDeposited = TimestampToDate(BitConverter.ToUInt64(data, 0xF8)); - TimeExchanged = TimestampToDate(BitConverter.ToUInt64(data, 0x100)); - PID = BitConverter.ToInt32(data, 0x108); - TrainerName = new EncodedString4(data, 0x10C, 0x10); - TrainerOT = BitConverter.ToUInt16(data, 0x11C); - TrainerCountry = data[0x11E]; - TrainerRegion = data[0x11F]; - TrainerClass = data[0x120]; - IsExchanged = data[0x121]; - TrainerVersion = data[0x122]; - TrainerLanguage = data[0x123]; + public override int Size + { + get { return 292; } } public GtsRecord4 Clone() @@ -187,47 +191,6 @@ namespace PkmnFoundations.Structures IsExchanged = 0x01; } - public static bool CheckLevels(byte min, byte max, byte other) - { - if (max == 0) max = 255; - return other >= min && other <= max; - } - - public static DateTime ? TimestampToDate(ulong timestamp) - { - if (timestamp == 0) return null; - - ushort year = (ushort)((timestamp >> 0x30) & 0xffff); - byte month = (byte)((timestamp >> 0x28) & 0xff); - byte day = (byte)((timestamp >> 0x20) & 0xff); - byte hour = (byte)((timestamp >> 0x18) & 0xff); - byte minute = (byte)((timestamp >> 0x10) & 0xff); - byte second = (byte)((timestamp >> 0x08) & 0xff); - //byte fractional = (byte)(timestamp & 0xff); // always 0 - - try - { - return new DateTime(year, month, day, hour, minute, second); - } - catch (ArgumentOutOfRangeException) - { - return null; - } - } - - public static ulong DateToTimestamp(DateTime ? date) - { - if (date == null) return 0; - DateTime date2 = (DateTime)date; - - return (ulong)(date2.Year & 0xffff) << 0x30 - | (ulong)(date2.Month & 0xff) << 0x28 - | (ulong)(date2.Day & 0xff) << 0x20 - | (ulong)(date2.Hour & 0xff) << 0x18 - | (ulong)(date2.Minute & 0xff) << 0x10 - | (ulong)(date2.Second & 0xff) << 0x08; - } - public static bool operator ==(GtsRecord4 a, GtsRecord4 b) { if ((object)a == null && (object)b == null) return true; diff --git a/library/Structures/GtsRecord5.cs b/library/Structures/GtsRecord5.cs index b9ca41a5..c01b1aea 100644 --- a/library/Structures/GtsRecord5.cs +++ b/library/Structures/GtsRecord5.cs @@ -13,19 +13,24 @@ namespace PkmnFoundations.Structures /// Includes a Pokémon box structure and metadata related to the trainer /// and request. /// - public class GtsRecord5 : IEquatable + public class GtsRecord5 : GtsRecordBase, IEquatable { - // todo: We should have a base class for Gen4/5 GTS records. - public GtsRecord5() { + Initialize(); } public GtsRecord5(byte[] data) { + Initialize(); Load(data); } + private void Initialize() + { + + } + // xxx: Data and Unknown0 should be one field. /// @@ -93,73 +98,72 @@ namespace PkmnFoundations.Structures public byte TrainerBadges; // speculative. Usually 8. public byte TrainerUnityTower; - public byte[] Save() + protected override void Save(BinaryWriter writer) { // todo: enclose in properties and validate these when assigning. if (Data.Length != 0xDC) throw new FormatException("PKM length is incorrect"); if (TrainerName.RawData.Length != 0x10) throw new FormatException("Trainer name length is incorrect"); - byte[] data = new byte[296]; - MemoryStream s = new MemoryStream(data); - s.Write(Data, 0, 0xDC); - s.Write(Unknown0, 0, 0x10); - s.Write(BitConverter.GetBytes(Species), 0, 2); - s.WriteByte((byte)Gender); - s.WriteByte(Level); - s.Write(BitConverter.GetBytes(RequestedSpecies), 0, 2); - s.WriteByte((byte)RequestedGender); - s.WriteByte(RequestedMinLevel); - s.WriteByte(RequestedMaxLevel); - s.WriteByte(Unknown1); - s.WriteByte((byte)TrainerGender); - s.WriteByte(Unknown2); - s.Write(BitConverter.GetBytes(GtsRecord4.DateToTimestamp(TimeDeposited)), 0, 8); - s.Write(BitConverter.GetBytes(GtsRecord4.DateToTimestamp(TimeExchanged)), 0, 8); - s.Write(BitConverter.GetBytes(PID), 0, 4); - s.Write(BitConverter.GetBytes(TrainerOT), 0, 4); - s.Write(TrainerName.RawData, 0, 0x10); - s.WriteByte(TrainerCountry); - s.WriteByte(TrainerRegion); - s.WriteByte(TrainerClass); - s.WriteByte(IsExchanged); - s.WriteByte(TrainerVersion); - s.WriteByte(TrainerLanguage); - s.WriteByte(TrainerBadges); - s.WriteByte(TrainerUnityTower); - s.Close(); - return data; + + writer.Write(Data, 0, 0xDC); // 0x0000 + writer.Write(Unknown0, 0, 0x10); // 0x00DC + + writer.Write(Species); // 0x00EC + writer.Write((byte)Gender); // 0x00EE + writer.Write(Level); // 0x00EF + writer.Write(RequestedSpecies); // 0x00F0 + writer.Write((byte)RequestedGender); // 0x00F2 + writer.Write(RequestedMinLevel); // 0x00F3 + writer.Write(RequestedMaxLevel); // 0x00F4 + writer.Write(Unknown1); // 0x00F5 + writer.Write((byte)TrainerGender); // 0x00F6 + writer.Write(Unknown2); // 0x00F7 + writer.Write(DateToTimestamp(TimeDeposited)); // 0x00F8 + writer.Write(DateToTimestamp(TimeExchanged)); // 0x0100 + writer.Write(PID); // 0x0108 + writer.Write(TrainerOT); // 0x010C + writer.Write(TrainerName.RawData, 0, 0x10); // 0x0110 + writer.Write(TrainerCountry); // 0x0120 + writer.Write(TrainerRegion); // 0x0121 + writer.Write(TrainerClass); // 0x0122 + writer.Write(IsExchanged); // 0x0123 + writer.Write(TrainerVersion); // 0x0124 + writer.Write(TrainerLanguage); // 0x0125 + writer.Write(TrainerBadges); // 0x0126 + writer.Write(TrainerUnityTower); // 0x0127 } - public void Load(byte[] data) + protected override void Load(BinaryReader reader) { - if (data.Length != 296) throw new FormatException("GTS record length is incorrect."); + Data = reader.ReadBytes(0xDC); // 0x0000 + Unknown0 = reader.ReadBytes(0x10); // 0x00DC + Species = reader.ReadUInt16(); // 0x00EC + Gender = (Genders)reader.ReadByte(); // 0x00EE + Level = reader.ReadByte(); // 0x00EF + RequestedSpecies = reader.ReadUInt16(); // 0x00F0 + RequestedGender = (Genders)reader.ReadByte(); // 0x00F2 + RequestedMinLevel = reader.ReadByte(); // 0x00F3 + RequestedMaxLevel = reader.ReadByte(); // 0x00F4 + Unknown1 = reader.ReadByte(); // 0x00F5 + TrainerGender = (TrainerGenders)reader.ReadByte(); // 0x00F6 + Unknown2 = reader.ReadByte(); // 0x00F7 + TimeDeposited = TimestampToDate(reader.ReadUInt64()); // 0x00F8 + TimeExchanged = TimestampToDate(reader.ReadUInt64()); // 0x0100 + PID = reader.ReadInt32(); // 0x0108 + TrainerOT = reader.ReadUInt32(); // 0x010C + TrainerName = new EncodedString5(reader.ReadBytes(0x10)); // 0x0110 + TrainerCountry = reader.ReadByte(); // 0x0120 + TrainerRegion = reader.ReadByte(); // 0x0121 + TrainerClass = reader.ReadByte(); // 0x0122 + IsExchanged = reader.ReadByte(); // 0x0123 + TrainerVersion = reader.ReadByte(); // 0x0124 + TrainerLanguage = reader.ReadByte(); // 0x0125 + TrainerBadges = reader.ReadByte(); // 0x0126 + TrainerUnityTower = reader.ReadByte(); // 0x0127 + } - Data = new byte[0xDC]; - Array.Copy(data, 0, Data, 0, 0xDC); - Unknown0 = new byte[0x10]; - Array.Copy(data, 0xDC, Unknown0, 0, 0x10); - Species = BitConverter.ToUInt16(data, 0xEC); - Gender = (Genders)data[0xEE]; - Level = data[0xEF]; - RequestedSpecies = BitConverter.ToUInt16(data, 0xF0); - RequestedGender = (Genders)data[0xF2]; - RequestedMinLevel = data[0xF3]; - RequestedMaxLevel = data[0xF4]; - Unknown1 = data[0xF5]; - TrainerGender = (TrainerGenders)data[0xF6]; - Unknown2 = data[0xF7]; - TimeDeposited = GtsRecord4.TimestampToDate(BitConverter.ToUInt64(data, 0xF8)); - TimeExchanged = GtsRecord4.TimestampToDate(BitConverter.ToUInt64(data, 0x100)); - PID = BitConverter.ToInt32(data, 0x108); - TrainerOT = BitConverter.ToUInt32(data, 0x10C); - TrainerName = new EncodedString5(data, 0x110, 0x10); - TrainerCountry = data[0x120]; - TrainerRegion = data[0x121]; - TrainerClass = data[0x122]; - IsExchanged = data[0x123]; - TrainerVersion = data[0x124]; - TrainerLanguage = data[0x125]; - TrainerBadges = data[0x126]; - TrainerUnityTower = data[0x127]; + public override int Size + { + get { return 296; } } public GtsRecord5 Clone() @@ -204,12 +208,6 @@ namespace PkmnFoundations.Structures IsExchanged = 0x01; } - public static bool CheckLevels(byte min, byte max, byte other) - { - if (max == 0) max = 255; - return other >= min && other <= max; - } - public static bool operator ==(GtsRecord5 a, GtsRecord5 b) { if ((object)a == null && (object)b == null) return true; diff --git a/library/Structures/GtsRecordBase.cs b/library/Structures/GtsRecordBase.cs new file mode 100644 index 00000000..0c46c986 --- /dev/null +++ b/library/Structures/GtsRecordBase.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace PkmnFoundations.Structures +{ + public abstract class GtsRecordBase : BinarySerializableBase + { + + + public static bool CheckLevels(byte min, byte max, byte other) + { + if (max == 0) max = 255; + return other >= min && other <= max; + } + + public static ulong DateToTimestamp(DateTime? date) + { + if (date == null) return 0; + DateTime date2 = (DateTime)date; + + return (ulong)(date2.Year & 0xffff) << 0x30 + | (ulong)(date2.Month & 0xff) << 0x28 + | (ulong)(date2.Day & 0xff) << 0x20 + | (ulong)(date2.Hour & 0xff) << 0x18 + | (ulong)(date2.Minute & 0xff) << 0x10 + | (ulong)(date2.Second & 0xff) << 0x08; + } + + public static DateTime? TimestampToDate(ulong timestamp) + { + if (timestamp == 0) return null; + + ushort year = (ushort)((timestamp >> 0x30) & 0xffff); + byte month = (byte)((timestamp >> 0x28) & 0xff); + byte day = (byte)((timestamp >> 0x20) & 0xff); + byte hour = (byte)((timestamp >> 0x18) & 0xff); + byte minute = (byte)((timestamp >> 0x10) & 0xff); + byte second = (byte)((timestamp >> 0x08) & 0xff); + //byte fractional = (byte)(timestamp & 0xff); // always 0 + + try + { + return new DateTime(year, month, day, hour, minute, second); + } + catch (ArgumentOutOfRangeException) + { + return null; + } + } + } +}