/AssemblyAnalyzer/Kokomo.Mirror/StructSerializer.cs
C# | 351 lines | 315 code | 36 blank | 0 comment | 87 complexity | 2daaa83ede231a391d847cb260fd4048 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.IO;
- using System.Reflection;
- using System.Collections;
-
- namespace Kokomo.Mirror
- {
- class StructSerializer : StructReaderBase
- {
- public StructSerializer(
- Stream stream,
- Encoding encoding = null
- )
- : base(stream)
- {
- if (encoding == null) encoding = Encoding.Default;
- this.BinaryReader = new BinaryReader(stream, encoding);
- }
-
- public BinaryReader BinaryReader { get; private set; }
-
- public TStruct ReadStruct<TStruct>()
- where TStruct : new()
- {
- TStruct struc = new TStruct();
- this.ReadStruct(struc);
- return struc;
- }
-
- public object ReadStruct(Type structType)
- {
- if (structType == null) throw new ArgumentNullException("structType");
- object instance = Activator.CreateInstance(structType);
- this.ReadStruct(instance);
- return instance;
- }
-
- public void ReadStruct(object instance)
- {
- if (instance == null) throw new ArgumentNullException("struc");
-
- BinaryReader reader = this.BinaryReader;
-
- Type structType = instance.GetType();
- MemberInfo[] members = structType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- Dictionary<string, bool> booleanFieldValues = new Dictionary<string, bool>();
- Dictionary<string, int> numericFieldValues = new Dictionary<string, int>();
- foreach (var member in members)
- {
- SerializedConditionAttribute conditionAttribute = (SerializedConditionAttribute)Attribute.GetCustomAttribute(member, typeof(SerializedConditionAttribute));
- if (conditionAttribute != null)
- {
- bool conditionValue = (bool)this.GetPropertyPathValue(instance, conditionAttribute.ConditionPropertyPath);
- if (!conditionValue) continue;
- }
- SerializedOffsetAttribute offsetAttribute = (SerializedOffsetAttribute)Attribute.GetCustomAttribute(member, typeof(SerializedOffsetAttribute));
- if (offsetAttribute != null)
- {
- int offset = Convert.ToInt32(this.GetPropertyPathValue(instance, offsetAttribute.OffsetPropertyName));
- this.Stream.Position = offset;
- }
-
- PropertyInfo property = member as PropertyInfo;
- if (property != null)
- {
- MethodInfo setter = property.GetSetMethod(true);
- if (setter == null) continue;
-
- NonSerializedAttribute nonSerializable = property.GetCustomAttribute<NonSerializedAttribute>();
- if (nonSerializable != null) continue;
-
- object propertyValue = null;
-
- SerializerContextFieldAttribute contextFieldAttribute = (SerializerContextFieldAttribute)Attribute.GetCustomAttribute(property, typeof(SerializerContextFieldAttribute));
- if (contextFieldAttribute != null)
- {
- switch (contextFieldAttribute.Field)
- {
- case SerializerContextField.Position32:
- propertyValue = (int)this.Stream.Position;
- break;
- case SerializerContextField.Position64:
- propertyValue = this.Stream.Position;
- break;
- }
- }
- else
- {
- propertyValue = this.ReadPropertyValue(property, property.PropertyType, instance);
- }
- if (propertyValue != null)
- {
- setter.Invoke(instance, new object[] { propertyValue });
- }
- }
- }
- }
-
- private object ReadPropertyValue(
- PropertyInfo property,
- Type propertyType,
- object instance
- )
- {
- object propertyValue = null;
-
- if (propertyType.IsArray)
- {
- int? length = this.DetermineLength(property, instance);
- propertyValue = this.ReadArray(property, instance, propertyType.GetElementType(), length);
- }
- else if (propertyType == typeof(string))
- {
- int? length = this.DetermineLength(property, instance);
- propertyValue = this.ReadString(length);
- }
- else if (propertyType.IsEnum || propertyType.IsPrimitive)
- {
- propertyValue = this.ReadValue(propertyType);
- }
- else
- {
- SerializeSwitchAttribute[] switchAttributes = (SerializeSwitchAttribute[])Attribute.GetCustomAttributes(property, typeof(SerializeSwitchAttribute));
- if (switchAttributes.Length > 0)
- {
- foreach (var switchAttribute in switchAttributes)
- {
- bool switchValue = (bool)GetPropertyPathValue(instance, switchAttribute.ConditionPropertyPath);
- if (switchValue)
- {
- propertyType = switchAttribute.StructType;
- break;
- }
- }
- }
-
- object propertyStruc = Activator.CreateInstance(propertyType);
- this.ReadStruct(propertyStruc);
- propertyValue = propertyStruc;
- }
-
- return propertyValue;
- }
-
- private object ReadValue(
- Type propertyType
- )
- {
- object propertyValue = null;
- if (propertyType.IsPrimitive)
- {
- propertyValue = ReadPrimitive(propertyType);
- }
- else if (propertyType.IsEnum)
- {
- object numericValue = ReadPrimitive(propertyType.GetEnumUnderlyingType());
- propertyValue = Enum.ToObject(propertyType, numericValue);
- }
- else
- {
- propertyValue = ReadStruct(propertyType);
- }
-
- return propertyValue;
- }
-
- private object GetPropertyPathValue(object instance, string propertyPath)
- {
- if (instance == null) throw new ArgumentNullException("instance");
- if (propertyPath == null) throw new ArgumentNullException("propertyName");
-
- string[] propertyNames = propertyPath.Split('.');
- foreach (var propertyName in propertyNames)
- {
- PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- object value = property.GetValue(instance, null);
- if (value == null) break;
- instance = value;
- }
-
- return instance;
- }
-
- private int? DetermineLength(
- PropertyInfo property,
- object instance
- )
- {
- if (property == null) throw new ArgumentNullException("property");
- if (instance == null) throw new ArgumentNullException("instance");
-
- SerializedArrayAttribute serializedStringAttribute = (SerializedArrayAttribute)Attribute.GetCustomAttribute(property, typeof(SerializedArrayAttribute));
- if (serializedStringAttribute == null) throw new InvalidOperationException("String property missing SerializedStringAttribute");
-
- BinaryReader reader = this.BinaryReader;
- int? length = null;
- switch (serializedStringAttribute.LengthEncoding)
- {
- case ArrayLengthEncoding.Fixed:
- length = serializedStringAttribute.FixedLength;
- break;
- case ArrayLengthEncoding.ByteCountPrefix16:
- case ArrayLengthEncoding.ElementCountPrefix16:
- length = reader.ReadInt16();
- break;
- case ArrayLengthEncoding.ByteCountPrefix32:
- length = reader.ReadInt32();
- break;
- case ArrayLengthEncoding.ElementCountPrefix32:
- break;
- case ArrayLengthEncoding.BytePrefixField:
- case ArrayLengthEncoding.ElementPrefixField:
- object prefixFieldValue = this.GetPropertyPathValue(instance, serializedStringAttribute.LengthFieldName);
- length = Convert.ToInt32(prefixFieldValue);
- break;
- case ArrayLengthEncoding.ZeroTerminated:
- break;
- }
-
- return length;
- }
-
- private object ReadPrimitive(Type type)
- {
- if (type == null) throw new ArgumentNullException("type");
-
- object value = null;
- BinaryReader reader = this.BinaryReader;
- if (type.IsPrimitive)
- {
- if (type == typeof(int))
- {
- value = reader.ReadInt32();
- }
- else if (type == typeof(IntPtr))
- {
- value = new IntPtr(reader.ReadInt32());
- }
- else if (type == typeof(uint))
- {
- value = reader.ReadUInt32();
- }
- else if (type == typeof(short))
- {
- value = reader.ReadInt16();
- }
- else if (type == typeof(ushort))
- {
- value = reader.ReadUInt16();
- }
- else if (type == typeof(byte))
- {
- value = reader.ReadByte();
- }
- else if (type == typeof(bool))
- {
- value = reader.ReadBoolean();
- }
- else if (type == typeof(long))
- {
- value = reader.ReadInt64();
- }
- else if (type == typeof(ulong))
- {
- value = reader.ReadUInt64();
- }
- else
- {
- throw new ArgumentException("Unknown type");
- }
- }
-
- return value;
- }
-
- public string ReadString(
- int? length
- )
- {
- string str;
- if (length.HasValue)
- {
- char[] chars = this.BinaryReader.ReadChars(length.Value);
- str = new string(chars);
- }
- else
- {
- StringBuilder builder = new StringBuilder();
- for (char c = this.BinaryReader.ReadChar(); c != '\0'; c = this.BinaryReader.ReadChar())
- {
- builder.Append(c);
- }
- str = builder.ToString();
- }
-
- return str;
- }
-
- public TElement[] ReadArray<TElement>(int? length)
- {
- return (TElement[])this.ReadArray(typeof(TElement), length, ReadValue);
- }
- protected Array ReadArray(PropertyInfo property, object instance, Type elementType, int? length)
- {
- return this.ReadArray(elementType, length, t => ReadPropertyValue(property, t, instance));
- }
- protected Array ReadArray(
- Type elementType,
- int? length,
- Func<Type, object> readerDelegate
- )
- {
- if (elementType == null) throw new ArgumentNullException("elementType");
- if (readerDelegate == null) throw new ArgumentNullException("readerDelegate");
-
- Array array;
-
- if (length.HasValue)
- {
- array = Array.CreateInstance(elementType, length.Value);
-
- for (int i = 0; i < array.Length; i++)
- {
- object element = readerDelegate(elementType);
- array.SetValue(element, i);
- }
- }
- else
- {
- List<object> list = new List<object>();
- object defaultInstance = Activator.CreateInstance(elementType);
-
- object element = null;
- while (true)
- {
- element = readerDelegate(elementType);
- if (object.Equals(element, defaultInstance)) break;
- list.Add(element);
- }
-
- array = Array.CreateInstance(elementType, list.Count);
- Array.Copy(list.ToArray(), array, array.Length);
- }
-
- return array;
- }
- }
- }