// /** // * File: ObjectWriter.cs // * Author: haraldwolff // * // * This file and it's content is copyrighted by the Author and / or copyright holder. // * Any use wihtout proper permission is illegal and may lead to legal actions. // * // * // **/ using System; using System.IO; using System.Text; using System.Reflection; using System.Linq; using System.Collections.Generic; using ln.types.sync; using System.Collections; namespace ln.types.serialize { /** * Types * * N null * b "false" * B "true" * 8 byte * 2 short * 4 int * L long * f float * d double * s string * 3 ushort * 5 uint * l ulong * S struct * A Array * T Type * L List<> * D Dictionary<> **/ public class ObjectWriter { public Stream Stream { get; } public object[] ReferencedObjects { get => referencedObjects.ToArray(); set => referencedObjects = new List(value); } List referencedObjects = new List(); public ObjectWriter(Stream stream) { Stream = stream; } private void WriteByte(char ch) { Stream.WriteByte((byte)ch); } public virtual object QueryReference(object o) { if (referencedObjects.Contains(o)) return referencedObjects.IndexOf(o); referencedObjects.Add(o); return o; } private object QueryObjectReplacement(object o) { Type type = o.GetType(); if (type.IsGenericType) { Type genericTypeDefinition = type.GetGenericTypeDefinition(); if (typeof(List<>).Equals(genericTypeDefinition)) { ListReplacement replacement = new ListReplacement(); replacement.elementType = type.GenericTypeArguments[0]; replacement.elements = new object[((IList)o).Count]; ((IList)o).CopyTo(replacement.elements, 0); return replacement; } else if (typeof(Dictionary<,>).Equals(genericTypeDefinition)) { DictionaryReplacement replacement = new DictionaryReplacement(); replacement.keyType = type.GenericTypeArguments[0]; replacement.valueType = type.GenericTypeArguments[1]; replacement.keys = new object[((IDictionary)o).Keys.Count]; ((IDictionary)o).Keys.CopyTo(replacement.keys, 0); replacement.values = new object[((IDictionary)o).Values.Count]; ((IDictionary)o).Values.CopyTo(replacement.values, 0); return replacement; } } return QueryReference(o); } public void Write(object o) { if (o == null) { WriteByte('N'); } else { Type type = o.GetType(); if (typeof(TypeInfo).IsInstanceOfType(o)) { WriteType((Type)o); } if (type.IsValueType || typeof(string).Equals(type)) { WriteValue(o); } else if (type.IsArray) { WriteArray(o as Array); } else { WriteObject(o); } } } private void WriteArray(Array a) { int length = a.Length; WriteByte('A'); WriteType(a.GetType().GetElementType()); WriteValue(length); for (int n = 0; n < length; n++) Write(a.GetValue(n)); } private void WriteFields(FieldInfo[] fieldInfos,object o) { WriteValue((int)fieldInfos.Length); foreach (FieldInfo fieldInfo in fieldInfos) { WriteValue(fieldInfo.Name); if (fieldInfo.GetCustomAttribute() != null) { WriteByte('N'); } else if (fieldInfo.FieldType == typeof(Type)) { WriteType((Type)fieldInfo.GetValue(o)); } else { Write(fieldInfo.GetValue(o)); } } } private void WriteType(Type type) { WriteByte('T'); WriteValue(type.Assembly.GetName().Name); if (type.IsGenericType) WriteValue(type.GetGenericTypeDefinition().FullName); else WriteValue(type.FullName); Type[] typeArgs = type.GenericTypeArguments; WriteValue(typeArgs.Length); foreach (Type typeArg in typeArgs) WriteType(typeArg); } private void WriteObject(object _o) { object o = QueryObjectReplacement(_o); if (o == _o) { Type type = o.GetType(); FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where((x) => !x.IsNotSerialized).ToArray(); WriteByte('O'); WriteType(type); WriteFields(fieldInfos, o); } else { WriteByte('o'); Write(o); } } private void WriteStruct(object o) { Type type = o.GetType(); FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public).Where((x) => !x.DeclaringType.Equals(typeof(object))).ToArray(); WriteByte('S'); WriteType(type); WriteFields(fieldInfos, o); } private void WriteValue(object value) { Type type = value.GetType(); if (typeof(String).Equals(type)) { WriteByte('s'); byte[] buffer = Encoding.UTF8.GetBytes(value as string); WriteValue(buffer.Length); Stream.Write(buffer, 0, buffer.Length); } else if (!type.IsPrimitive) { WriteStruct(value); } else if (typeof(Boolean).Equals(type)) { WriteByte((bool)value ? 'B' : 'b'); } else if (typeof(byte).Equals(type)) { WriteByte('8'); Stream.WriteByte((byte)value); } else if (typeof(short).Equals(type)) { WriteByte('2'); Stream.Write(BitConverter.GetBytes((short)value),0,2); } else if (typeof(int).Equals(type)) { WriteByte('4'); Stream.Write(BitConverter.GetBytes((int)value), 0, 4); } else if (typeof(long).Equals(type)) { WriteByte('L'); Stream.Write(BitConverter.GetBytes((long)value), 0, 8); } else if (typeof(float).Equals(type)) { WriteByte('f'); Stream.Write(BitConverter.GetBytes((float)value), 0, 4); } else if (typeof(double).Equals(type)) { WriteByte('d'); Stream.Write(BitConverter.GetBytes((double)value), 0, 8); } else if (typeof(ushort).Equals(type)) { WriteByte('3'); Stream.Write(BitConverter.GetBytes((ushort)value), 0, 2); } else if (typeof(uint).Equals(type)) { WriteByte('5'); Stream.Write(BitConverter.GetBytes((uint)value), 0, 4); } else if (typeof(ulong).Equals(type)) { WriteByte('l'); Stream.Write(BitConverter.GetBytes((ulong)value), 0, 8); } else { throw new NotImplementedException(); } } } }