private static int GetByteSize(FieldInfo fieldInfo, FieldTypeId id, SerializationHintsAttribute attribute) { if (attribute != null && attribute.BitPacked > 0) { switch (id) { case FieldTypeId.Class: case FieldTypeId.Double: case FieldTypeId.Single: case FieldTypeId.Struct: case FieldTypeId.String: throw new NotSupportedException("Cannot specify BitPacket hint for this field."); } if ((attribute.BitPacked % 8) != 0) { throw new NotSupportedException("Number of bits in BitPacked must be dividable by 8 to get complecte bytes."); } return(attribute.BitPacked / 8); } if (id == FieldTypeId.Enum) { Type underlayingType = Enum.GetUnderlyingType(fieldInfo.FieldType); switch (Type.GetTypeCode(underlayingType)) { case TypeCode.Byte: case TypeCode.SByte: return(1); case TypeCode.Int16: case TypeCode.UInt16: return(2); case TypeCode.Int32: case TypeCode.UInt32: return(4); case TypeCode.Int64: case TypeCode.UInt64: return(8); } } return(byteSizes[(int)id]); }
private static FieldTypeId GetFieldTypeId(FieldInfo fieldInfo, SerializationHintsAttribute attribute) { Type type = fieldInfo.FieldType; if (type.IsPrimitive) { switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: if (attribute != null && attribute.RangeBias != 0) throw new NotSupportedException("RangeBias not allowed for fields of type bool."); if (attribute != null && attribute.Scale != 0) throw new NotSupportedException("Scale not allowed for fields of type bool."); return FieldTypeId.Boolean; case TypeCode.Byte: return FieldTypeId.Byte; case TypeCode.SByte: return FieldTypeId.SByte; case TypeCode.Char: return FieldTypeId.Char; case TypeCode.UInt16: return FieldTypeId.UInt16; case TypeCode.Int16: return FieldTypeId.Int32; case TypeCode.UInt32: return FieldTypeId.UInt32; case TypeCode.Int32: return FieldTypeId.Int32; case TypeCode.UInt64: return FieldTypeId.UInt64; case TypeCode.Int64: return FieldTypeId.Int64; case TypeCode.Single: return FieldTypeId.Single; case TypeCode.Double: return FieldTypeId.Double; default: throw new NotSupportedException("Unsupported primitive."); } } switch (Type.GetTypeCode(type)) { case TypeCode.String: return FieldTypeId.String; case TypeCode.DateTime: return FieldTypeId.DateTime; default: if (type == typeof(TimeSpan)) return FieldTypeId.TimeSpan; if (type.IsEnum) return FieldTypeId.Enum; if (type.IsValueType) { if ((type.Attributes & ~TypeAttributes.Serializable) != 0) return FieldTypeId.Struct; else return FieldTypeId.NonSerializableFieldType; } if (type.IsInterface) throw new NotSupportedException("Fields that are interfaces are not possible to serialize."); if (type.IsClass) { if (type.IsArray) throw new NotSupportedException("Fields that are arrays are not supported."); if ((type.Attributes & ~TypeAttributes.Serializable) != 0) { if (type == typeof(Type)) throw new NotSupportedException("Fields of type Type not possible to serialize."); if (type.IsAbstract) throw new NotSupportedException("Fields that are of abstract types are not possible to serialize."); if (!type.IsSealed && (attribute == null || (attribute.Flags & SerializationFlags.FixedType) == 0)) throw new NotSupportedException("Fields that are classes must be of a sealed class or must be marked as fixed type with the SerializationHintsAttribute.Flags."); if(attribute == null || (attribute.Flags & SerializationFlags.PointerNeverNull) == 0) throw new NotSupportedException("Fields that are classes cannot be null and must be marked with SerializationFlags.PointerNeverNull."); return FieldTypeId.Class; } return FieldTypeId.NonSerializableFieldType; } throw new NotSupportedException("Unsupported field type."); } }
private static int GetByteSize(FieldInfo fieldInfo, FieldTypeId id, SerializationHintsAttribute attribute) { if (attribute != null && attribute.BitPacked > 0) { switch (id) { case FieldTypeId.Class: case FieldTypeId.Double: case FieldTypeId.Single: case FieldTypeId.Struct: case FieldTypeId.String: throw new NotSupportedException("Cannot specify BitPacket hint for this field."); } if ((attribute.BitPacked % 8) != 0) throw new NotSupportedException("Number of bits in BitPacked must be dividable by 8 to get complecte bytes."); return attribute.BitPacked / 8; } if (id == FieldTypeId.Enum) { Type underlayingType = Enum.GetUnderlyingType(fieldInfo.FieldType); switch (Type.GetTypeCode(underlayingType)) { case TypeCode.Byte: case TypeCode.SByte: return 1; case TypeCode.Int16: case TypeCode.UInt16: return 2; case TypeCode.Int32: case TypeCode.UInt32: return 4; case TypeCode.Int64: case TypeCode.UInt64: return 8; } } return byteSizes[(int)id]; }
private static FieldTypeId GetFieldTypeId(FieldInfo fieldInfo, SerializationHintsAttribute attribute) { Type type = fieldInfo.FieldType; if (type.IsPrimitive) { switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: if (attribute != null && attribute.RangeBias != 0) { throw new NotSupportedException("RangeBias not allowed for fields of type bool."); } if (attribute != null && attribute.Scale != 0) { throw new NotSupportedException("Scale not allowed for fields of type bool."); } return(FieldTypeId.Boolean); case TypeCode.Byte: return(FieldTypeId.Byte); case TypeCode.SByte: return(FieldTypeId.SByte); case TypeCode.Char: return(FieldTypeId.Char); case TypeCode.UInt16: return(FieldTypeId.UInt16); case TypeCode.Int16: return(FieldTypeId.Int32); case TypeCode.UInt32: return(FieldTypeId.UInt32); case TypeCode.Int32: return(FieldTypeId.Int32); case TypeCode.UInt64: return(FieldTypeId.UInt64); case TypeCode.Int64: return(FieldTypeId.Int64); case TypeCode.Single: return(FieldTypeId.Single); case TypeCode.Double: return(FieldTypeId.Double); default: throw new NotSupportedException("Unsupported primitive."); } } switch (Type.GetTypeCode(type)) { case TypeCode.String: return(FieldTypeId.String); case TypeCode.DateTime: return(FieldTypeId.DateTime); default: if (type == typeof(TimeSpan)) { return(FieldTypeId.TimeSpan); } if (type.IsEnum) { return(FieldTypeId.Enum); } if (type.IsValueType) { if ((type.Attributes & ~TypeAttributes.Serializable) != 0) { return(FieldTypeId.Struct); } else { return(FieldTypeId.NonSerializableFieldType); } } if (type.IsInterface) { throw new NotSupportedException("Fields that are interfaces are not possible to serialize."); } if (type.IsClass) { if (type.IsArray) { throw new NotSupportedException("Fields that are arrays are not supported."); } if ((type.Attributes & ~TypeAttributes.Serializable) != 0) { if (type == typeof(Type)) { throw new NotSupportedException("Fields of type Type not possible to serialize."); } if (type.IsAbstract) { throw new NotSupportedException("Fields that are of abstract types are not possible to serialize."); } if (!type.IsSealed && (attribute == null || (attribute.Flags & SerializationFlags.FixedType) == 0)) { throw new NotSupportedException("Fields that are classes must be of a sealed class or must be marked as fixed type with the SerializationHintsAttribute.Flags."); } if (attribute == null || (attribute.Flags & SerializationFlags.PointerNeverNull) == 0) { throw new NotSupportedException("Fields that are classes cannot be null and must be marked with SerializationFlags.PointerNeverNull."); } return(FieldTypeId.Class); } return(FieldTypeId.NonSerializableFieldType); } throw new NotSupportedException("Unsupported field type."); } }
private static void DeSerializeField(MemoryStream stream, object obj, FieldInfo fieldInfo) { SerializationHintsAttribute attribute = GetSerializationHintsAttribute(fieldInfo); FieldTypeId id = GetFieldTypeId(fieldInfo, attribute); if (id == FieldTypeId.NonSerializableFieldType) { return; } int byteCount = GetByteSize(fieldInfo, id, attribute); ulong binValue; if (id != FieldTypeId.String && id != FieldTypeId.Class && id != FieldTypeId.Struct) { binValue = ReadUnsignedLong(stream, byteCount); } else { binValue = 0; } object value = null; switch (id) { case FieldTypeId.Boolean: value = binValue != 0; break; case FieldTypeId.Byte: value = (byte)binValue; break; case FieldTypeId.SByte: value = (sbyte)binValue; break; case FieldTypeId.Char: value = (char)binValue; break; case FieldTypeId.UInt16: value = (ushort)binValue; break; case FieldTypeId.Int16: value = (short)binValue; break; case FieldTypeId.UInt32: value = (uint)binValue; break; case FieldTypeId.Int32: value = (int)binValue; break; case FieldTypeId.UInt64: value = (ulong)binValue; break; case FieldTypeId.Int64: value = (long)binValue; break; case FieldTypeId.Enum: Type underlayingType = Enum.GetUnderlyingType(fieldInfo.FieldType); switch (Type.GetTypeCode(underlayingType)) { case TypeCode.Byte: value = (byte)binValue; break; case TypeCode.SByte: value = (sbyte)binValue; break; case TypeCode.Int16: value = (short)binValue; break; case TypeCode.UInt16: value = (ushort)binValue; break; case TypeCode.Int32: value = (int)binValue; break; case TypeCode.UInt32: value = (uint)binValue; break; case TypeCode.Int64: value = (long)binValue; break; case TypeCode.UInt64: value = (ulong)binValue; break; } break; case FieldTypeId.Single: value = BitConverter.ToSingle(BitConverter.GetBytes((uint)binValue), 0); break; case FieldTypeId.Double: value = BitConverter.ToDouble(BitConverter.GetBytes((ulong)binValue), 0); break; case FieldTypeId.DateTime: value = new DateTime((long)binValue); break; case FieldTypeId.TimeSpan: value = new TimeSpan((long)binValue); break; case FieldTypeId.String: uint count = ReadCompressedUnsigned(stream); if (count != uint.MaxValue) { byte[] bytes = new byte[count]; stream.Read(bytes, 0, (int)count); value = Encoding.UTF8.GetString(bytes); } else { value = null; } break; case FieldTypeId.Struct: case FieldTypeId.Class: value = DeSerializeObject(stream, fieldInfo.FieldType); break; default: throw new NotSupportedException(); } fieldInfo.SetValue(obj, value); }
private static void SerializeField(MemoryStream stream, object obj, FieldInfo fieldInfo) { object value = fieldInfo.GetValue(obj); ulong binValue; SerializationHintsAttribute attribute = GetSerializationHintsAttribute(fieldInfo); FieldTypeId id = GetFieldTypeId(fieldInfo, attribute); switch (id) { case FieldTypeId.Boolean: binValue = ((bool)value) ? (ulong)1 : (ulong)0; break; case FieldTypeId.Byte: binValue = (byte)value; break; case FieldTypeId.SByte: binValue = (ulong)(sbyte)value; break; case FieldTypeId.Char: binValue = (char)value; break; case FieldTypeId.UInt16: binValue = (ushort)value; break; case FieldTypeId.Int16: binValue = (ulong)(short)value; break; case FieldTypeId.UInt32: binValue = (uint)value; break; case FieldTypeId.Int32: binValue = (ulong)(int)value; break; case FieldTypeId.UInt64: binValue = (ulong)value; break; case FieldTypeId.Int64: binValue = (ulong)(long)value; break; case FieldTypeId.Enum: Type underlayingType = Enum.GetUnderlyingType(fieldInfo.FieldType); switch (Type.GetTypeCode(underlayingType)) { case TypeCode.Byte: binValue = (byte)value; break; case TypeCode.SByte: binValue = (ulong)(sbyte)value; break; case TypeCode.Int16: binValue = (ulong)(short)value; break; case TypeCode.UInt16: binValue = (ushort)value; break; case TypeCode.Int32: binValue = (ulong)(int)value; break; case TypeCode.UInt32: binValue = (uint)value; break; case TypeCode.Int64: binValue = (ulong)(long)value; break; case TypeCode.UInt64: binValue = (ulong)value; break; default: throw new NotSupportedException("Invalid enum."); } break; case FieldTypeId.Single: binValue = BitConverter.ToUInt32(BitConverter.GetBytes((float)value), 0); break; case FieldTypeId.Double: binValue = BitConverter.ToUInt64(BitConverter.GetBytes((double)value), 0); break; case FieldTypeId.DateTime: binValue = (ulong)((DateTime)value).Ticks; break; case FieldTypeId.TimeSpan: binValue = (ulong)((TimeSpan)value).Ticks; break; case FieldTypeId.String: if (value != null) { byte[] bytes = Encoding.UTF8.GetBytes((string)value); WriteCompressedUnsigned(stream, (uint)bytes.Length); stream.Write(bytes, 0, bytes.Length); } else { WriteCompressedUnsigned(stream, uint.MaxValue); } return; case FieldTypeId.Struct: SerializeObject(stream, value, fieldInfo.FieldType); return; case FieldTypeId.Class: if (value == null) { throw new NotSupportedException("Fields which are classes must not be null."); } SerializeObject(stream, value, fieldInfo.FieldType); return; case FieldTypeId.NonSerializableFieldType: return; default: throw new NotSupportedException(); } int byteCount = GetByteSize(fieldInfo, id, attribute); WriteUnsignedLong(stream, binValue, byteCount); }