289 lines
8.3 KiB
C#
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();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|