private object ReadRawObject(BinaryReader reader, object item, int baseOffset) { var properties = item.GetType() .GetProperties() .Select(x => GetPropertySettings(item.GetType(), x)) .Where(x => x.DataInfo != null) .ToList(); var args = new MappingReadArgs { Reader = reader }; foreach (var property in properties) { if (property.DataInfo.Offset.HasValue) { var newPosition = baseOffset + property.DataInfo.Offset.Value; if (reader.BaseStream.Position != newPosition + 1) { args.BitIndex = 0; } reader.BaseStream.Position = newPosition; } args.Count = property.GetLengthFunc?.Invoke(item) ?? property.DataInfo.Count; var value = ReadProperty(args, property.MemberInfo.PropertyType, property); property.MemberInfo.SetValue(item, value, BindingFlags.Default, null, null, null); } args.BitIndex = 0; return(item); }
private object ReadProperty(MappingReadArgs args, Type type, MyProperty property) { if (type != typeof(bool)) { args.BitIndex = 0; } if (mappings.TryGetValue(type, out var mapping)) { args.DataAttribute = property.DataInfo; return(mapping.Reader(args)); } else if (type.IsEnum) { var underlyingType = Enum.GetUnderlyingType(type); if (!mappings.TryGetValue(underlyingType, out mapping)) { throw new InvalidDataException($"The enum {type.Name} has an unsupported size."); } args.DataAttribute = property.DataInfo; return(mapping.Reader(args)); } else if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(List <>))) { var listType = type.GetGenericArguments().FirstOrDefault(); if (listType == null) { throw new InvalidDataException($"The list {property.MemberInfo.Name} does not have any specified type."); } var addMethod = type.GetMethod("Add"); var list = Activator.CreateInstance(typeof(List <>).MakeGenericType(listType)); for (int i = 0; i < args.Count; i++) { var oldPosition = (int)args.Reader.BaseStream.Position; var item = ReadProperty(args, listType, property); addMethod.Invoke(list, new[] { item }); var newPosition = args.Reader.BaseStream.Position; args.Reader.BaseStream.Position += Math.Max(0, property.DataInfo.Stride - (newPosition - oldPosition)); } return(list); } else if (type.IsArray) { if (type.GetArrayRank() > 1) { throw new NotImplementedException("Arrays with a rank greater than one are not currently supported."); } var arrayType = type.GetElementType(); if (arrayType == null) { throw new InvalidDataException($"Unable to get the underlying type of {type.Name}."); } var array = Array.CreateInstance(arrayType, args.Count); if (arrayType.IsEnum) { for (var i = 0; i < args.Count; i++) { var oldPosition = (int)args.Reader.BaseStream.Position; var item = ReadProperty(args, arrayType, property); array.SetValue(Enum.ToObject(arrayType, item), i); var newPosition = args.Reader.BaseStream.Position; args.Reader.BaseStream.Position += Math.Max(0, property.DataInfo.Stride - (newPosition - oldPosition)); } } else { for (var i = 0; i < args.Count; i++) { var oldPosition = (int)args.Reader.BaseStream.Position; var item = ReadProperty(args, arrayType, property); array.SetValue(item, i); var newPosition = args.Reader.BaseStream.Position; args.Reader.BaseStream.Position += Math.Max(0, property.DataInfo.Stride - (newPosition - oldPosition)); } } return(array); } else { return(ReadRawObject(args.Reader, Activator.CreateInstance(type), (int)args.Reader.BaseStream.Position)); } }