/// <summary> /// Unserializes the fields of an object from a binary reader. /// </summary> /// <param name="writer">Writer to unpack fields into.</param> /// <param name="obj">Object to unpack fields of.</param> private void UnPackObjectFields(BinaryReader reader, object obj) { // Write in field values. FieldInfo[] properties = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); // Order fields by names in alphabetical order. properties = properties.OrderBy(j => j.Name).ToArray(); // Read number of fields. byte fieldCount = reader.ReadByte(); if (properties.Length != fieldCount) { throw new IndexOutOfRangeException("Packet contains an invalid number of fields."); } // Read in fields hash and check if its correct. byte realHash = reader.ReadByte(); PearsonHash hash = new PearsonHash(); foreach (FieldInfo field in properties) { byte[] bytes = StringHelper.StringToByteArray(field.Name); hash.AddBuffer(bytes, 0, bytes.Length); } // Check hash is correct. if (hash.Calculate() != realHash) { throw new FormatException("Packet structure appears to be different from packet class."); } for (int i = 0; i < fieldCount; i++) { PacketPackedFieldType fieldType = (PacketPackedFieldType)reader.ReadByte(); FieldInfo field = properties[i]; Type realFieldType = field.FieldType; // Is array or normal? if (((byte)fieldType & (byte)PacketPackedFieldType.Array) != 0) { // Is field an array. if (realFieldType.IsArray != true) { throw new FormatException("Packet contains invalid field data type."); } // Strip "Array" from field type. fieldType = (PacketPackedFieldType)(((byte)fieldType) & ~((int)PacketPackedFieldType.Array)); // Read in array. Type elementType = realFieldType.GetElementType(); int arrayDimensions = reader.ReadByte(); Array array = null; int[] arrayLengths = new int[arrayDimensions]; int[] arrayLowerBounds = new int[arrayDimensions]; // Read in array lengths. for (int l = 0; l < arrayDimensions; l++) { arrayLengths[l] = reader.ReadInt32(); arrayLowerBounds[l] = 0; } // Create the array. array = Array.CreateInstance(elementType, arrayLengths, arrayLowerBounds); if (fieldType == PacketPackedFieldType.Null) { array = null; } else if (fieldType == PacketPackedFieldType.String) { // Is field correct data type. if (elementType != typeof(string)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { if (reader.ReadBoolean() == true) { array.SetValue(reader.ReadString(), val.Indicies); } else { array.SetValue(null, val.Indicies); } } } else if (fieldType == PacketPackedFieldType.Byte) { // Is field correct data type. if (elementType != typeof(byte)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadByte(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.UShort) { // Is field correct data type. if (elementType != typeof(ushort)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadUInt16(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.Short) { // Is field correct data type. if (elementType != typeof(short)) { throw new IndexOutOfRangeException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadInt16(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.UInt) { // Is field correct data type. if (elementType != typeof(uint)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadUInt32(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.Bool) { // Is field correct data type. if (elementType != typeof(bool)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadBoolean(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.Int) { // Is field correct data type. if (elementType != typeof(int)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadInt32(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.ULong) { // Is field correct data type. if (elementType != typeof(ulong)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadUInt64(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.Long) { // Is field correct data type. if (elementType != typeof(long)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadInt64(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.Float) { // Is field correct data type. if (elementType != typeof(float)) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadSingle(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.Double) { // Is field correct data type. if (elementType != typeof(double)) { throw new IndexOutOfRangeException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { array.SetValue(reader.ReadDouble(), val.Indicies); } } else if (fieldType == PacketPackedFieldType.Struct) { // Is field correct data type. if (elementType.IsValueType != true && elementType.IsClass != true) { throw new FormatException("Packet contains invalid field data type."); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { if (reader.ReadBoolean() == true) { object structResult = Activator.CreateInstance(elementType);//FormatterServices.GetUninitializedObject(realFieldType); UnPackObjectFields(reader, structResult); array.SetValue(structResult, val.Indicies); } else { array.SetValue(null, val.Indicies); } } } else { throw new FormatException("Packet contains invalid field data type."); } // Set the field value. field.SetValue(obj, array); } else { if (fieldType == PacketPackedFieldType.Null) { // Is field correct data type. if (realFieldType.IsByRef == false && realFieldType.IsValueType == false && realFieldType.IsClass == false) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, null); } else if (fieldType == PacketPackedFieldType.String) { // Is field correct data type. if (realFieldType != typeof(string)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadString()); } else if (fieldType == PacketPackedFieldType.Byte) { // Is field correct data type. if (realFieldType != typeof(byte)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadByte()); } else if (fieldType == PacketPackedFieldType.UShort) { // Is field correct data type. if (realFieldType != typeof(ushort)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadUInt16()); } else if (fieldType == PacketPackedFieldType.Short) { // Is field correct data type. if (realFieldType != typeof(short)) { throw new IndexOutOfRangeException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadInt16()); } else if (fieldType == PacketPackedFieldType.UInt) { // Is field correct data type. if (realFieldType != typeof(uint)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadUInt32()); } else if (fieldType == PacketPackedFieldType.Bool) { // Is field correct data type. if (realFieldType != typeof(bool)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadBoolean()); } else if (fieldType == PacketPackedFieldType.Int) { // Is field correct data type. if (realFieldType != typeof(int)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadInt32()); } else if (fieldType == PacketPackedFieldType.ULong) { // Is field correct data type. if (realFieldType != typeof(ulong)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadUInt64()); } else if (fieldType == PacketPackedFieldType.Long) { // Is field correct data type. if (realFieldType != typeof(long)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadInt64()); } else if (fieldType == PacketPackedFieldType.Float) { // Is field correct data type. if (realFieldType != typeof(float)) { throw new FormatException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadSingle()); } else if (fieldType == PacketPackedFieldType.Double) { // Is field correct data type. if (realFieldType != typeof(double)) { throw new IndexOutOfRangeException("Packet contains invalid field data type."); } field.SetValue(obj, reader.ReadDouble()); } else if (fieldType == PacketPackedFieldType.Struct) { // Is field correct data type. if (realFieldType.IsValueType != true && realFieldType.IsClass != true) { throw new FormatException("Packet contains invalid field data type."); } object structResult = null; if (reader.ReadBoolean() == true) { structResult = Activator.CreateInstance(realFieldType); //FormatterServices.GetUninitializedObject(realFieldType); // UnPackObjectFields(reader, structResult); } field.SetValue(obj, structResult); } else { throw new FormatException("Packet contains invalid field data type."); } } } }
/// <summary> /// Serializes the fields of an object into a binary writer. /// </summary> /// <param name="writer">Writer to pack fields into.</param> /// <param name="obj">Object to pack fields of.</param> private void PackObjectFields(BinaryWriter writer, object obj) { // Write in field values. FieldInfo[] properties = obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); // Order fields by names in alphabetical order. properties = properties.OrderBy(j => j.Name).ToArray(); // Write number of fields. if (properties.Length >= 255) { throw new IndexOutOfRangeException("Packet can only have a maximum of 255 public fields."); } writer.Write((byte)properties.Length); // Write in hash code of fields. PearsonHash hash = new PearsonHash(); foreach (FieldInfo field in properties) { byte[] bytes = StringHelper.StringToByteArray(field.Name); hash.AddBuffer(bytes, 0, bytes.Length); } writer.Write((byte)hash.Calculate()); // Write in the fields! foreach (FieldInfo field in properties) { Type fieldType = field.FieldType; object fieldValue = field.GetValue(obj); // Null. if (fieldValue == null) { writer.Write((byte)PacketPackedFieldType.Null); } // String. else if (fieldType == typeof(string)) { writer.Write((byte)PacketPackedFieldType.String); writer.Write((string)fieldValue); } // Integer types. else if (fieldType == typeof(byte)) { writer.Write((byte)PacketPackedFieldType.Byte); writer.Write((byte)fieldValue); } else if (fieldType == typeof(ushort)) { writer.Write((byte)PacketPackedFieldType.UShort); writer.Write((ushort)fieldValue); } else if (fieldType == typeof(short)) { writer.Write((byte)PacketPackedFieldType.Short); writer.Write((short)fieldValue); } else if (fieldType == typeof(uint)) { writer.Write((byte)PacketPackedFieldType.UInt); writer.Write((uint)fieldValue); } else if (fieldType == typeof(int)) { writer.Write((byte)PacketPackedFieldType.Int); writer.Write((int)fieldValue); } else if (fieldType == typeof(bool)) { writer.Write((byte)PacketPackedFieldType.Bool); writer.Write((bool)fieldValue); } else if (fieldType == typeof(ulong)) { writer.Write((byte)PacketPackedFieldType.ULong); writer.Write((ulong)fieldValue); } else if (fieldType == typeof(long)) { writer.Write((byte)PacketPackedFieldType.Long); writer.Write((long)fieldValue); } // Floating point types. else if (fieldType == typeof(float)) { writer.Write((byte)PacketPackedFieldType.Float); writer.Write((float)fieldValue); } else if (fieldType == typeof(double)) { writer.Write((byte)PacketPackedFieldType.Double); writer.Write((double)fieldValue); } // Other types of data. else { // An array. if (fieldType.IsArray) { Array array = ((Array)fieldValue); Type elementType = fieldType.GetElementType(); // Null if (array == null) { writer.Write((byte)(PacketPackedFieldType.Null | PacketPackedFieldType.Array)); writer.Write((byte)0); } // String. else if (elementType == typeof(string)) { writer.Write((byte)(PacketPackedFieldType.String | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write(val.Value != null); if (val.Value != null) { writer.Write((string)val.Value); } } } // Integer types. else if (elementType == typeof(byte)) { writer.Write((byte)(PacketPackedFieldType.Byte | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((byte)val.Value); } } else if (elementType == typeof(ushort)) { writer.Write((byte)(PacketPackedFieldType.UShort | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((ushort)val.Value); } } else if (elementType == typeof(short)) { writer.Write((byte)(PacketPackedFieldType.Short | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((short)val.Value); } } else if (elementType == typeof(uint)) { writer.Write((byte)(PacketPackedFieldType.UInt | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((uint)val.Value); } } else if (elementType == typeof(bool)) { writer.Write((byte)(PacketPackedFieldType.Bool | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((bool)val.Value); } } else if (elementType == typeof(int)) { writer.Write((byte)(PacketPackedFieldType.Int | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((int)val.Value); } } else if (elementType == typeof(ulong)) { writer.Write((byte)(PacketPackedFieldType.ULong | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((ulong)val.Value); } } else if (elementType == typeof(long)) { writer.Write((byte)(PacketPackedFieldType.Long | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((long)val.Value); } } // Floating point types. else if (elementType == typeof(float)) { writer.Write((byte)(PacketPackedFieldType.Float | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((float)val.Value); } } else if (elementType == typeof(double)) { writer.Write((byte)(PacketPackedFieldType.Double | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write((double)val.Value); } } // Structs maybe? else if (elementType.IsValueType == true || elementType.IsClass == true) { writer.Write((byte)(PacketPackedFieldType.Struct | PacketPackedFieldType.Array)); writer.Write((byte)fieldType.GetArrayRank()); // Write in dimension lengths. for (int rank = 0; rank < fieldType.GetArrayRank(); rank++) { int length = array.GetLength(rank); writer.Write((int)length); } // Write in values. MultiDimensionArrayIterator iterator = new MultiDimensionArrayIterator(array); foreach (MultiDimensionArrayIteratorValue val in iterator) { writer.Write(val.Value != null); if (val.Value != null) { PackObjectFields(writer, val.Value); } } } // Invalid data type. else { throw new IndexOutOfRangeException("Packet contains an invalid data type for packing '" + elementType.Name + "'."); } } // Structs maybe? else if (fieldType.IsValueType == true || fieldType.IsClass == true) { writer.Write((byte)PacketPackedFieldType.Struct); writer.Write(fieldValue != null); PackObjectFields(writer, fieldValue); } // Invalid data type. else { throw new IndexOutOfRangeException("Packet contains an invalid data type for packing '" + fieldType.Name + "'."); } } } }