using ln.type; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; namespace ln.objects.serialization.binary { public class BinarySerializer : Serializer { public override bool SerializeObject(object o, out byte[] serializedBytes) { MemoryStream serializedStream = new MemoryStream(); Type type = o.GetType(); if (type.IsPrimitive || (type == typeof(string))) SerializePrimitive(serializedStream, o); else if (type.IsEnum) SerializeEnum(serializedStream, o); else if (type.IsValueType) SerializeValue(serializedStream, o); else if (type.IsArray) SerializeArray(serializedStream, o); else SerializeStructured(serializedStream, o); serializedBytes = serializedStream.ToArray(); return true; } void Serialize(Stream stream, object o) { if (Object.ReferenceEquals(null, o)) { stream.WriteByte('0'); } else { Type type = o.GetType(); if (type.IsPrimitive || (type == typeof(string))) SerializePrimitive(stream, o); else if (type.IsEnum) SerializeEnum(stream, o); else if (type.IsValueType) SerializeValue(stream, o); else if (type.IsArray) SerializeArray(stream, o); else { if (TryLookupReference(o, out object reference)) { stream.WriteByte('R'); SerializePrimitive(stream, type.GetSimpleQualifiedName()); Serialize(stream, reference); } else { SerializeStructured(stream, o); } } } } void SerializePrimitive(Stream stream, object value) { stream.WriteByte('P'); if (value is int i) { stream.WriteByte('I'); stream.WriteInteger(i); } else if (value is uint ui) { stream.WriteByte('i'); stream.WriteUInteger(ui); } else if (value is byte b) { stream.WriteByte('B'); stream.WriteByte(b); } else if (value is char ch) { stream.WriteByte('C'); stream.WriteShort((short)ch); } else if (value is short sh) { stream.WriteByte('S'); stream.WriteShort(sh); } else if (value is ushort us) { stream.WriteByte('s'); stream.WriteUShort(us); } else if (value is long il) { stream.WriteByte('L'); stream.WriteLong(il); } else if (value is ulong ul) { stream.WriteByte('l'); stream.WriteULong(ul); } else if (value is float f) { stream.WriteByte('F'); stream.WriteFloat(f); } else if (value is double d) { stream.WriteByte('D'); stream.WriteDouble(d); } else if (value is bool bo) { stream.WriteByte('b'); stream.WriteByte(bo ? (byte)0x01 : (byte)0x00); } else if (value is string str) { stream.WriteByte('T'); byte[] bytes = Encoding.UTF8.GetBytes(str); stream.WriteInteger(bytes.Length); stream.WriteBytes(bytes); } else throw new NotSupportedException(String.Format("Unsupported primitive type: {0}", value.GetType().Name)); // ToDo: Add struct System.Decimal } void SerializeEnum(Stream stream, object value) { Type eType = value.GetType(); stream.WriteByte('E'); SerializePrimitive(stream, eType.GetSimpleQualifiedName()); if (eType.GetCustomAttribute() != null) SerializePrimitive(stream, (int)value); else SerializePrimitive(stream, value.ToString()); } void SerializeArray(Stream stream, object value) { if (value is byte[] ba) { stream.WriteByte('B'); stream.WriteInteger(ba.Length); stream.WriteBytes(ba); } else { Array array = (Array)value; stream.WriteByte('A'); SerializePrimitive(stream, array.GetType().GetElementType().GetSimpleQualifiedName()); stream.WriteInteger(array.Length); for (int n = 0; n < array.Length; n++) Serialize(stream, array.GetValue(n)); } } void SerializeValue(Stream stream, object value) { Type valueType = value.GetType(); if (value is Guid guid) { stream.WriteByte('G'); stream.WriteBytes(guid.ToByteArray()); } else SerializeStructured(stream, value); } void SerializeStructured(Stream stream, object value) { Type type = value.GetType(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); stream.WriteByte('S'); SerializePrimitive(stream, type.GetSimpleQualifiedName()); stream.WriteInteger(fields.Length); foreach (FieldInfo fieldInfo in fields) { object v = fieldInfo.GetValue(value); if (MangleValue(fieldInfo.FieldType, ref v)) fieldInfo.SetValue(value, v); SerializePrimitive(stream, fieldInfo.Name); Serialize(stream, v); } } } }