private void DeserializeFields(BinaryReader reader, ControllerSerializationContext serializationContext, object instance) { if (reader == null) { throw new ArgumentNullException(nameof(reader)); } if (serializationContext == null) { throw new ArgumentNullException(nameof(serializationContext)); } if (instance == null) { throw new ArgumentNullException(nameof(instance)); } FieldInfo[] fields = serializationContext.Type.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo field in fields) { var ctx = new ControllerSerializationContext(field, serializationContext.Controller); var value = DeserializeField(reader, ctx); // We have our value, set it. field.SetValue(instance, value); } }
/// <inheritdoc /> public object Deserialize(BinaryReader reader, ControllerSerializationContext serializationContext) { var list = (IList)Activator.CreateInstance(serializationContext.Type); Type[] typeArgs = serializationContext.Type.GetGenericArguments(); Type elementType = typeArgs[0]; var innerContext = new ControllerSerializationContext(elementType, serializationContext.Controller); if (serializationContext.Controller is AnimationController) { // Read n times, determined by prefixed count field. int count = reader.ReadUInt16(); for (int i = 0; i < count; i++) { list.Add(_controllerFieldSerializer.ReadField(reader, innerContext)); } } else { // Read until end of stream. while (reader.BaseStream.Position < reader.BaseStream.Length) { list.Add(_controllerFieldSerializer.ReadField(reader, innerContext)); } } return(list); }
/// <inheritdoc /> public override DateTime Deserialize(BinaryReader reader, ControllerSerializationContext serializationContext) { string sDate = reader.ReadInt32().ToString(); if (DateTime.TryParseExact(sDate, DateFormat, null, DateTimeStyles.None, out DateTime date)) { return(date); } // If a parse error occurred, this most like is because the days of month are 31, for instance for april, or 30-31 for feb, or even 29 if not a leap year. Correct this by attempting to parse by lowering the days. int days = int.Parse(sDate.Substring(6, 2)); sDate = sDate.Remove(6); // 3 extra attempts max. for (var i = 0; i < 3; i++) { days--; if (DateTime.TryParseExact(sDate + days, DateFormat, null, DateTimeStyles.None, out date)) { return(date); } } throw new FormatException($"The date {sDate} is in unexpected format."); }
/// <inheritdoc /> public override void Serialize(BinaryWriter writer, ControllerSerializationContext serializationContext, string value) { if (value != null) { // Write the variable string with one zero. writer.Write((string)value, '\0'); } }
public DateTimeValueSerializerTests() { _sut = new DateTimeValueSerializer(); FieldInfo field = typeof(TestClass).GetField(nameof(TestClass.Supported)); _serializationContext = new ControllerSerializationContext(field, new Mock <Controller>().Object); }
/// <inheritdoc /> public override string Deserialize(BinaryReader reader, ControllerSerializationContext serializationContext) { if (reader.BaseStream.Position == reader.BaseStream.Length) { return(null); } return(reader.ReadNullTerminatedString()); }
/// <inheritdoc /> public void Serialize(BinaryWriter writer, ControllerSerializationContext serializationContext, object value) { if (value == null) { // TODO: check if null we can actually write... return; } writer.WriteStruct(value); }
/// <summary> /// Writes specified <paramref name="value"/> using the <paramref name="writer"/>. /// </summary> /// <param name="writer">The writer to serialize to.</param> /// <param name="serializationContext">The serialization context.</param> /// <param name="value">The value to serialize.</param> protected virtual void WriteField(BinaryWriter writer, ControllerSerializationContext serializationContext, object value) { if (serializationContext.Type.IsControllerOrObject()) { SerializeFields(writer, serializationContext, value); } else { WriteValue(writer, serializationContext, value); } }
private void WriteValue(BinaryWriter writer, ControllerSerializationContext ctx, object value) { IControllerValueSerializer serializer = _serializers.FirstOrDefault(s => s.IsSupported(ctx)); if (serializer == null) { throw new NotImplementedException($"The specified type '{ctx.Type.FullName}' is not supported or implemented."); } serializer.Serialize(writer, ctx, value); }
/// <inheritdoc /> public object Deserialize(BinaryReader reader, ControllerSerializationContext serializationContext) { Type underlyingType = Nullable.GetUnderlyingType(serializationContext.Type); var innerContext = new ControllerSerializationContext(underlyingType, serializationContext.Controller); IControllerValueSerializer serializer = _serializers.FirstOrDefault(s => s.IsSupported(innerContext)); return(serializer != null ? serializer.Deserialize(reader, serializationContext) : reader.ReadStruct(underlyingType)); }
private object ReadValue(BinaryReader reader, ControllerSerializationContext ctx) { IControllerValueSerializer serializer = _serializers.FirstOrDefault(s => s.IsSupported(ctx)); object result = serializer?.Deserialize(reader, ctx); if (result == null) { throw new NotImplementedException($"The specified type '{ctx.Type.FullName}' is not supported or implemented."); } return(result); }
/// <inheritdoc /> public override void Serialize(BinaryWriter writer, ControllerSerializationContext serializationContext, string value) { int fixedLength = serializationContext.Member.GetCustomAttribute <FixedStringAttribute>().Length; string s = (string)value ?? string.Empty; if (s.Length > fixedLength) { throw new InvalidOperationException($"The string '{s}' for property '{serializationContext.Member.Name}' exceeds the fixed length {fixedLength}"); } // Write the fixed string with zeros at the end. writer.Write(s, fixedLength); }
public void Given_value_when_serializing_should_write_value_type(Type typeWithSupportedField, object value) { FieldInfo field = typeWithSupportedField.GetField("Supported"); var serializationContext = new ControllerSerializationContext(field, new Mock <Controller>().Object); using (var ms = new MemoryStream()) using (var writer = new BinaryWriter(ms, FileEncoding.Default)) { // Act _sut.Serialize(writer, serializationContext, value); // Assert BitConverter.GetBytes((int)value).Should().Equal(ms.ToArray()); } }
/// <inheritdoc /> protected override void Deserialize(BinaryReader reader, ControllerSerializationContext serializationContext, object instance) { // Read the size of the controller. int size = reader.ReadInt32(); // Save current position of stream. At the end, we compare the size with the number of bytes read for validation purposes. long startPos = reader.BaseStream.Position; string controllerName = serializationContext.Type.Name; reader.SkipMember(serializationContext.Type, controllerName); base.Deserialize(reader, serializationContext, instance); reader.BaseStream.EnsureStreamPosition(startPos + size, controllerName); }
/// <inheritdoc /> public override bool Deserialize(BinaryReader reader, ControllerSerializationContext serializationContext) { long boolLen = reader.BaseStream.Length; switch (boolLen) { case 1: return(reader.ReadByte() > 0); case 4: return(reader.ReadInt32() > 0); default: throw new FormatException($"Unable to convert {boolLen} bytes into a boolean."); } }
/// <inheritdoc /> protected override void SerializeField(BinaryWriter writer, ControllerSerializationContext serializationContext, object value) { // If the value is null, the property has be optional, otherwise throw error. if (value == null && serializationContext.Type != typeof(string)) { if (serializationContext.Member.HasAttribute <OptionalAttribute>()) { return; } string fieldName = serializationContext.Member.GetCustomAttribute <ParseNameAttribute>()?.Name ?? serializationContext.Name; throw new SilentHunterParserException($"The field '{fieldName}' is not defined as optional."); } base.SerializeField(writer, serializationContext, value); }
public void Given_serialized_value_type_when_deserializing_should_return_typed_value_type(object value, Type expectedType) { FieldInfo field = expectedType.GetField("Supported"); var serializationContext = new ControllerSerializationContext(field, new Mock <Controller>().Object); using (var ms = new MemoryStream(BitConverter.GetBytes((int)value))) using (var reader = new BinaryReader(ms, FileEncoding.Default)) { // Act object actual = _sut.Deserialize(reader, serializationContext); // Assert actual.Should() .BeOfType(field.FieldType) .And.Be(value); } }
/// <inheritdoc /> public void Serialize(BinaryWriter writer, ControllerSerializationContext serializationContext, object value) { if (value is byte[] byteArray) { // Slightly more efficient to write directly. writer.Write(byteArray, 0, byteArray.Length); return; } // Otherwise write each primitive separately. var array = (Array)value; for (var i = 0; i < array.Length; i++) { writer.WriteStruct(array.GetValue(i)); } }
/// <summary> /// Reads a field from the <paramref name="reader"/>. /// </summary> /// <param name="reader">The reader to deserialize from.</param> /// <param name="serializationContext">The serialization context.</param> protected virtual object ReadField(BinaryReader reader, ControllerSerializationContext serializationContext) { object retVal; if (serializationContext.Type.IsControllerOrObject()) { // Create a new instance of this type. retVal = Activator.CreateInstance(serializationContext.Type); DeserializeFields(reader, serializationContext, retVal); } else { retVal = ReadValue(reader, serializationContext); } return(retVal); }
/// <inheritdoc /> protected override object DeserializeField(BinaryReader reader, ControllerSerializationContext serializationContext) { object value = base.DeserializeField(reader, serializationContext); // Strings can have null are always optional. if (value != null || serializationContext.Type == typeof(string)) { return(value); } // If null is returned, check if the field is optional and if the type supports a nullable type. if (serializationContext.Type.IsValueType && !serializationContext.Type.IsNullable()) { throw new SilentHunterParserException( $"The property '{serializationContext.Name}' is defined as optional, but the type '{serializationContext.Type}' does not support null values. Use Nullable<> if the property is a value type, or a class otherwise."); } return(null); }
/// <inheritdoc /> public override string Deserialize(BinaryReader reader, ControllerSerializationContext serializationContext) { int fixedLength = serializationContext.Member.GetCustomAttribute <FixedStringAttribute>().Length; if (reader.BaseStream.Length > fixedLength) { throw new SilentHunterParserException($"The stream contains more data than expected for '{serializationContext.Member.Name}', length {fixedLength}."); } if (reader.BaseStream.Length < fixedLength) { throw new SilentHunterParserException($"The stream does not contain enough data for '{serializationContext.Member.Name}', length {fixedLength}."); } string s = reader.ReadString(fixedLength); // Take care of possible '\0' char in middle of string. return(s.Split(new[] { '\0' }, 2, StringSplitOptions.None)[0]); }
/// <inheritdoc /> public void Serialize(BinaryWriter writer, ControllerSerializationContext serializationContext, object value) { var list = (IList)value; Type[] typeArgs = serializationContext.Type.GetGenericArguments(); Type elementType = typeArgs[0]; var innerContext = new ControllerSerializationContext(elementType, serializationContext.Controller); if (serializationContext.Controller is AnimationController) { // Output count field. writer.Write(unchecked ((ushort)list.Count)); } foreach (object item in list) { _controllerFieldSerializer.WriteField(writer, innerContext, item); } }
/// <inheritdoc /> protected override object ReadField(BinaryReader reader, ControllerSerializationContext serializationContext) { string name = null; var field = serializationContext.Member as FieldInfo; if (field != null) { if (field.HasAttribute <OptionalAttribute>() && reader.BaseStream.Position == reader.BaseStream.Length) { // Exit because field is optional, and we are at end of stream. return(null); } // The expected field or controller name to find on the stream. name = field.GetCustomAttribute <ParseNameAttribute>()?.Name ?? field.Name; } // Read the size of the data. int size = reader.ReadInt32(); // Save current position of stream. At the end, we compare the size with the number of bytes read for validation purposes. long startPos = reader.BaseStream.Position; if (field != null && !string.IsNullOrEmpty(name) && reader.SkipMember(field, name)) { // The property must be skipped, so revert stream back to the start position. reader.BaseStream.Position = startPos - 4; return(null); } long expectedPosition = startPos + size; long dataSize = expectedPosition - reader.BaseStream.Position; using (var regionStream = new RegionStream(reader.BaseStream, dataSize)) { using (var regionReader = new BinaryReader(regionStream, FileEncoding.Default, true)) { object retVal = base.ReadField(regionReader, serializationContext); reader.BaseStream.EnsureStreamPosition(expectedPosition, name ?? serializationContext.Name); return(retVal); } } }
/// <summary> /// Serializes specified <paramref name="controller"/> to the <paramref name="stream"/>. /// </summary> /// <param name="stream">The stream to serialize to.</param> /// <param name="controller">The controller instance to serialize.</param> public void Serialize(Stream stream, Controller controller) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (controller == null) { throw new ArgumentNullException(nameof(controller)); } Type controllerType = controller.GetType(); using (var writer = new BinaryWriter(stream, FileEncoding.Default, true)) { var ctx = new ControllerSerializationContext(controllerType, controller); Serialize(writer, ctx, controller); } }
private void SerializeFields(BinaryWriter writer, ControllerSerializationContext serializationContext, object instance) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (instance == null) { throw new ArgumentNullException(nameof(instance)); } FieldInfo[] fields = serializationContext.Type.GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo field in fields) { var ctx = new ControllerSerializationContext(field, serializationContext.Controller); object value = field.GetValue(instance); SerializeField(writer, ctx, value); } }
/// <inheritdoc /> public object Deserialize(BinaryReader reader, ControllerSerializationContext serializationContext) { long dataSize = reader.BaseStream.Length - reader.BaseStream.Position; SHUnionPropertyCache propertyCache = GetCachedProperties(serializationContext.Type); Type[] typeArgs = serializationContext.Type.GetGenericArguments(); // Using size of data to determine which of the SHUnion generic type arguments to use. Type valueType = typeArgs.FirstOrDefault(type => Marshal.SizeOf(type) == dataSize); if (valueType == null) { throw new SilentHunterParserException($"The available stream data does not match the size one of the two union types for property '{serializationContext.Name}'."); } object union = Activator.CreateInstance(serializationContext.Type); propertyCache.TypeProperty.SetValue(union, valueType, null); propertyCache.ValueProperty.SetValue(union, reader.ReadStruct(valueType), null); return(union); }
/// <inheritdoc /> protected override void WriteField(BinaryWriter writer, ControllerSerializationContext serializationContext, object value) { // Write size 0. We don't know actual the size yet. writer.Write(0); long startPos = writer.BaseStream.Position; if (serializationContext.Member is FieldInfo fieldInfo) { string name = fieldInfo.GetCustomAttribute <ParseNameAttribute>()?.Name ?? fieldInfo.Name; writer.WriteNullTerminatedString(name); } base.WriteField(writer, serializationContext, value); // Rewind and store size. long currentPos = writer.BaseStream.Position; writer.BaseStream.Position = startPos - 4; writer.Write((int)(currentPos - startPos)); writer.BaseStream.Position = currentPos; }
/// <summary> /// Deserializes specified <paramref name="controller"/> from the <paramref name="stream"/>. /// </summary> /// <param name="stream">The stream to deserialize from.</param> /// <param name="controller">The controller instance to populate with deserialized data.</param> public void Deserialize(Stream stream, Controller controller) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } if (controller == null) { throw new ArgumentNullException(nameof(controller)); } Type controllerType = controller.GetType(); using (var reader = new BinaryReader(stream, FileEncoding.Default, true)) { var ctx = new ControllerSerializationContext(controllerType, controller); Deserialize(reader, ctx, controller); reader.BaseStream.EnsureStreamPosition(reader.BaseStream.Length, controllerType.Name); } }
/// <inheritdoc /> protected override void Serialize(BinaryWriter writer, ControllerSerializationContext serializationContext, object instance) { // We don't know the size yet, so just write 0 for now. writer.Write(0); // Save current position of stream. At the end, we have to set the size. long startPos = writer.BaseStream.Position; string controllerName = serializationContext.Type.Name; writer.WriteNullTerminatedString(controllerName); base.Serialize(writer, serializationContext, instance); // After the object is written, determine and write the size. long currentPos = writer.BaseStream.Position; writer.BaseStream.Position = startPos - 4; writer.Write((int)(currentPos - startPos)); // Restore position to the end of the controller. writer.BaseStream.Position = currentPos; }
/// <inheritdoc /> public override void Serialize(BinaryWriter writer, ControllerSerializationContext serializationContext, DateTime value) { string date = value.ToString("yyyyMMdd"); writer.Write(int.Parse(date)); }