ln.types/serialize/ObjectWriter.cs

289 lines
8.3 KiB
C#

// /**
// * 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<object>(value);
}
List<object> referencedObjects = new List<object>();
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<Unsynced>() != 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();
}
}
}
}