#region License Information /* HeuristicLab * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using Google.ProtocolBuffers; using HeuristicLab.Persistence.Core; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; namespace HeuristicLab.Persistence { public abstract class BoxTransformer : Transformer { public override bool CanTransformType(Type type) { return type == typeof(T); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); box.TypeId = mapper.GetBoxId(o.GetType()); Populate(box, (T)o, mapper); return box.Build(); } public override object ToObject(Box box, Mapper mapper) { return Extract(box, (Type)mapper.GetObject(box.TypeId), mapper); } protected abstract void Populate(Box.Builder box, T value, Mapper mapper); protected abstract T Extract(Box box, Type type, Mapper mapper); } #region Scalar Box Transformers public abstract class BoolBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = BoolBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(BoolBox.Bool, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(BoolBox.Bool).Value, type, mapper); } protected abstract bool ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(bool value, Type type, Mapper mapper); } public abstract class IntBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = IntBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(IntBox.Int, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(IntBox.Int).Value, type, mapper); } protected abstract int ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(int value, Type type, Mapper mapper); } public abstract class LongBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = LongBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(LongBox.Long, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(LongBox.Long).Value, type, mapper); } protected abstract long ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(long value, Type type, Mapper mapper); } public abstract class UnsignedIntBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = UnsignedIntBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(UnsignedIntBox.UnsignedInt, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(UnsignedIntBox.UnsignedInt).Value, type, mapper); } protected abstract uint ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(uint value, Type type, Mapper mapper); } public abstract class UnsignedLongBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = UnsignedLongBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(UnsignedLongBox.UnsignedLong, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(UnsignedLongBox.UnsignedLong).Value, type, mapper); } protected abstract ulong ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(ulong value, Type type, Mapper mapper); } public abstract class FloatBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = FloatBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(FloatBox.Float, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(FloatBox.Float).Value, type, mapper); } protected abstract float ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(float value, Type type, Mapper mapper); } public abstract class DoubleBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = DoubleBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(DoubleBox.Double, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(DoubleBox.Double).Value, type, mapper); } protected abstract double ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(double value, Type type, Mapper mapper); } public abstract class StringBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = StringBox.CreateBuilder(); b.Value = ToBoxType(value, mapper); box.SetExtension(StringBox.String, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(StringBox.String).Value, type, mapper); } protected abstract string ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(string value, Type type, Mapper mapper); } public abstract class BytesBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = BytesBox.CreateBuilder(); b.Value = ByteString.CopyFrom(ToBoxType(value, mapper)); box.SetExtension(BytesBox.Bytes, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(BytesBox.Bytes).Value.ToByteArray(), type, mapper); } protected abstract byte[] ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(byte[] value, Type type, Mapper mapper); } #endregion #region Array Box Transformers public abstract class ByteArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = ByteArrayBox.CreateBuilder(); b.SetValues(ToByteString(value)); box.SetExtension(ByteArrayBox.ByteArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return FromByteString(box.GetExtension(ByteArrayBox.ByteArray).Values); } protected abstract ByteString ToByteString(T value); protected abstract T FromByteString(ByteString byteString); } public abstract class BoolArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = BoolArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(BoolArrayBox.BoolArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(BoolArrayBox.BoolArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } public abstract class IntArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = IntArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(IntArrayBox.IntArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(IntArrayBox.IntArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } public abstract class LongArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = LongArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(LongArrayBox.LongArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(LongArrayBox.LongArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } public abstract class UnsignedIntArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = UnsignedIntArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } public abstract class UnsignedLongArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = UnsignedLongArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(UnsignedLongArrayBox.UnsignedLongArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(UnsignedLongArrayBox.UnsignedLongArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } public abstract class FloatArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = FloatArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(FloatArrayBox.FloatArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(FloatArrayBox.FloatArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } public abstract class DoubleArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = DoubleArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(DoubleArrayBox.DoubleArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(DoubleArrayBox.DoubleArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } public abstract class StringArrayBoxTransformer : BoxTransformer { protected override void Populate(Box.Builder box, T value, Mapper mapper) { var b = StringArrayBox.CreateBuilder(); b.AddRangeValues(ToBoxType(value, mapper)); box.SetExtension(StringArrayBox.StringArray, b.Build()); } protected override T Extract(Box box, Type type, Mapper mapper) { return ToValueType(box.GetExtension(StringArrayBox.StringArray).ValuesList, type, mapper); } protected abstract IEnumerable ToBoxType(T value, Mapper mapper); protected abstract T ToValueType(IEnumerable value, Type type, Mapper mapper); } #endregion [Transformer("11B822C9-46A0-4B65-AE4A-D12F63DDE9F6", 50)] internal sealed class TypeTransformer : Transformer { public override bool CanTransformType(Type type) { return typeof(Type).IsAssignableFrom(type); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var type = (Type)value; var typeBox = TypeBox.CreateBuilder(); if (type.IsGenericType) { box.TypeId = mapper.GetTypeId(type.GetGenericTypeDefinition()); typeBox.AddRangeGenericTypeIds(type.GetGenericArguments().Select(t => mapper.GetBoxId(t))); } else if (type.IsArray) { box.TypeId = mapper.GetTypeId(typeof(Array)); typeBox.AddGenericTypeIds(mapper.GetBoxId(type.GetElementType())); } else { box.TypeId = mapper.GetTypeId(type); } if (StorableTypeAttribute.IsStorableType(type)) typeBox.Version = StorableTypeAttribute.GetStorableTypeAttribute(type).Version; box.SetExtension(TypeBox.Type, typeBox.Build()); } public override object ToObject(Box box, Mapper mapper) { return Extract(box, mapper.GetType(box.TypeId), mapper); } private object Extract(Box box, Type type, Mapper mapper) { var b = box.GetExtension(TypeBox.Type); if (type.IsGenericType) { return type.MakeGenericType(b.GenericTypeIdsList.Select(id => (Type)mapper.GetObject(id)).ToArray()); } else if (type == typeof(Array)) { return ((Type)mapper.GetObject(b.GetGenericTypeIds(0))).MakeArrayType(); } else { return type; } } } #region Primitive Value Types [Transformer("268617FE-3F0F-4029-8248-EDA420901FB6", 10000)] internal sealed class ObjectTransformer : BoxTransformer { protected override void Populate(Box.Builder box, object value, Mapper mapper) { } protected override object Extract(Box box, Type type, Mapper mapper) { return new object(); } } [Transformer("9FA1C6A8-517E-4623-AC1B-7E9AEF6ED13D", 200)] internal sealed class BoolTransformer : BoolBoxTransformer { protected override bool ToBoxType(bool value, Mapper mapper) { return value; } protected override bool ToValueType(bool value, Type type, Mapper mapper) { return value; } } [Transformer("059633E9-12CB-43EC-8544-57746536E281", 201)] internal sealed class ByteTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(byte value, Mapper mapper) { return value; } protected override byte ToValueType(uint value, Type type, Mapper mapper) { return (byte)value; } } [Transformer("5DC2F3AC-0852-4B57-A861-D29CC814A94C", 202)] internal sealed class SByteTransformer : IntBoxTransformer { protected override int ToBoxType(sbyte value, Mapper mapper) { return value; } protected override sbyte ToValueType(int value, Type type, Mapper mapper) { return (sbyte)value; } } [Transformer("B862E642-A94A-4870-8065-06126A35A9E1", 203)] internal sealed class ShortTransformer : IntBoxTransformer { protected override int ToBoxType(short value, Mapper mapper) { return value; } protected override short ToValueType(int value, Type type, Mapper mapper) { return (short)value; } } [Transformer("D1D3062D-F1BB-4189-AE50-D6986E1DEB4E", 204)] internal sealed class UShortTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(ushort value, Mapper mapper) { return value; } protected override ushort ToValueType(uint value, Type type, Mapper mapper) { return (ushort)value; } } [Transformer("6C444645-3062-4D15-AD01-E6E1B0692A2B", 205)] internal sealed class CharTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(char value, Mapper mapper) { return value; } protected override char ToValueType(uint value, Type type, Mapper mapper) { return (char)value; } } [Transformer("649E73B2-EFA6-4E01-BCB4-4B29D652C9CB", 206)] internal sealed class IntTransformer : IntBoxTransformer { protected override int ToBoxType(int value, Mapper mapper) { return value; } protected override int ToValueType(int value, Type type, Mapper mapper) { return value; } } [Transformer("BCF25010-81A2-49BC-88CC-407D3F393D5B", 207)] internal sealed class UIntTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(uint value, Mapper mapper) { return value; } protected override uint ToValueType(uint value, Type type, Mapper mapper) { return value; } } [Transformer("B6F6ACAE-755C-47EE-B8BF-7CDECBE19C30", 208)] internal sealed class LongTransformer : LongBoxTransformer { protected override long ToBoxType(long value, Mapper mapper) { return value; } protected override long ToValueType(long value, Type type, Mapper mapper) { return value; } } [Transformer("82333ACA-F041-44E0-B365-27C399594BA7", 209)] internal sealed class ULongTransformer : UnsignedLongBoxTransformer { protected override ulong ToBoxType(ulong value, Mapper mapper) { return value; } protected override ulong ToValueType(ulong value, Type type, Mapper mapper) { return value; } } [Transformer("8FE91ECF-2261-4934-BECD-C38923B7A703", 210)] internal sealed class FloatTransformer : FloatBoxTransformer { protected override float ToBoxType(float value, Mapper mapper) { return value; } protected override float ToValueType(float value, Type type, Mapper mapper) { return value; } } [Transformer("070D23EA-7F38-46B7-A667-219BEF914E49", 211)] internal sealed class DoubleTransformer : DoubleBoxTransformer { protected override double ToBoxType(double value, Mapper mapper) { return value; } protected override double ToValueType(double value, Type type, Mapper mapper) { return value; } } [Transformer("BA55C7A6-C91E-4351-A889-E4A7E647F16D", 212)] internal sealed class DateTimeTransformer : LongBoxTransformer { protected override long ToBoxType(DateTime value, Mapper mapper) { return value.Ticks; } protected override DateTime ToValueType(long value, Type type, Mapper mapper) { return new DateTime(value); } } [Transformer("0C91441B-2D97-432B-B493-D6EC483FC5AD", 213)] internal sealed class TimeSpanTransformer : LongBoxTransformer { protected override long ToBoxType(TimeSpan value, Mapper mapper) { return value.Ticks; } protected override TimeSpan ToValueType(long value, Type type, Mapper mapper) { return new TimeSpan(value); } } [Transformer("0B540EAC-79AB-40CF-8277-D2C81135FEB6", 214)] internal sealed class ColorTransformers : IntBoxTransformer { protected override int ToBoxType(Color value, Mapper mapper) { return value.ToArgb(); } protected override Color ToValueType(int value, Type type, Mapper mapper) { return Color.FromArgb(value); } } [Transformer("2E6D4A40-B4BE-425F-8E35-2D7C00054639", 215)] internal sealed class PointTransformer : IntArrayBoxTransformer { protected override IEnumerable ToBoxType(Point value, Mapper mapper) { return new int[] { value.X, value.Y }; } protected override Point ToValueType(IEnumerable value, Type type, Mapper mapper) { return new Point(value.ElementAt(0), value.ElementAt(1)); } } [Transformer("97B5CFC8-CDFA-4EB5-B4CD-5B3CFA5CD844", 216)] internal sealed class KeyValuePairTransformer : BoxTransformer { public override bool CanTransformType(Type type) { return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)); } protected override void Populate(Box.Builder box, object value, Mapper mapper) { var b = UnsignedIntArrayBox.CreateBuilder(); var type = value.GetType(); var pair = new uint[2]; pair[0] = mapper.GetBoxId(type.GetProperty("Key").GetValue(value)); pair[1] = mapper.GetBoxId(type.GetProperty("Value").GetValue(value)); b.AddRangeValues(pair); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, b.Build()); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var b = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var key = mapper.GetObject(b.GetValues(0)); var val = mapper.GetObject(b.GetValues(1)); var type = obj.GetType(); //DataMemberAccessor.GenerateFieldSetter(type.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance))(obj, key); //DataMemberAccessor.GenerateFieldSetter(type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance))(obj, val); type.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, key); type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, val); } protected override object Extract(Box box, Type type, Mapper mapper) { return Activator.CreateInstance(type); } } [Transformer("EBD8BF65-D97D-4FD4-BF4F-9D58A72B6249", 217)] internal sealed class DecimalTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(decimal value, Mapper mapper) { return mapper.GetStringId(FormatG30(value)); } protected override decimal ToValueType(uint value, Type type, Mapper mapper) { var converter = TypeDescriptor.GetConverter(typeof(Font)); return ParseG30(mapper.GetString(value)); } private static decimal ParseG30(string s) { decimal d; if (decimal.TryParse(s, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out d)) return d; throw new FormatException( string.Format("Invalid decimal G30 number format \"{0}\" could not be parsed", s)); } private static string FormatG30(decimal d) { return d.ToString("g30", CultureInfo.InvariantCulture); } } #endregion #region String [Transformer("E75A594C-0034-4DAB-B28E-8F84F9F6DE8D", 218)] internal sealed class StringTransformer : UnsignedIntBoxTransformer { protected override uint ToBoxType(string value, Mapper mapper) { return mapper.GetStringId(value); } protected override string ToValueType(uint value, Type type, Mapper mapper) { return mapper.GetString(value); } } #endregion #region Enum [Transformer("93FF076B-BC4B-4C39-8C40-15E004468C98", 219)] internal sealed class EnumTransformer : Transformer { public override bool CanTransformType(Type type) { return typeof(Enum).IsAssignableFrom(type); } public override Box ToBox(object o, Mapper mapper) { var boxBuilder = Box.CreateBuilder(); var enumBuilder = new UnsignedIntBox.Builder(); boxBuilder.TransformerId = mapper.GetTransformerId(this); boxBuilder.TypeId = mapper.GetStringId(o.GetType().AssemblyQualifiedName); enumBuilder.Value = mapper.GetStringId(Enum.Format(o.GetType(), o, "G")); boxBuilder.SetExtension(UnsignedIntBox.UnsignedInt, enumBuilder.Build()); return boxBuilder.Build(); } public override object ToObject(Box box, Mapper mapper) { uint value = box.GetExtension(UnsignedIntBox.UnsignedInt).Value; return Enum.Parse(Type.GetType(mapper.GetString(box.TypeId)), mapper.GetString(value)); } } #endregion #region Struct [Transformer("89DAAFC5-726C-48D4-A4E0-2B0D27329642", 220)] internal sealed class StructTransformer : Transformer { public override bool CanTransformType(Type type) { return type.IsValueType && !type.IsPrimitive && !type.IsEnum && type.IsSealed; } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } public override object ToObject(Box box, Mapper mapper) { return Extract(box, (Type)mapper.GetObject(box.TypeId), mapper); } private void Populate(Box.Builder box, object value, Mapper mapper) { var b = StorableClassBox.CreateBuilder(); var type = value.GetType(); var components = new Dictionary(); foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) { var component = mapper.GetBoxId(fieldInfo.GetValue(value)); components.Add(mapper.GetStringId(fieldInfo.Name), component); } b.AddRangeKeyIds(components.Keys); b.AddRangeValueIds(components.Values); box.TypeId = mapper.GetBoxId(type); box.SetExtension(StorableClassBox.StorableClass, b.Build()); } private object Extract(Box box, Type type, Mapper mapper) { var data = box.GetExtension(StorableClassBox.StorableClass); var obj = Activator.CreateInstance(type); var components = new Dictionary(); for (int i = 0; i < data.KeyIdsList.Count; i++) { components.Add(data.KeyIdsList[i], data.ValueIdsList[i]); } foreach (var t in components) { string name = mapper.GetString(t.Key); MemberInfo[] mis = type.GetMember(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (mis.Length != 1) throw new Exception("ambiguous struct member name " + name); MemberInfo mi = mis[0]; if(StorableAttribute.IsStorable(mi)) throw new PersistenceException("Don't use stroable attributes for structs as all fields are serialized automatically."); if (mi.MemberType == MemberTypes.Field) ((FieldInfo)mi).SetValue(obj, mapper.GetObject(t.Value)); else throw new Exception("invalid struct member type " + mi.MemberType.ToString()); } return obj; } } #endregion #region Tuple [Transformer("63A19D57-EEEF-4346-9F06-B35B15EBFFA3", 221)] internal sealed class TupleTransformer : Transformer { private static readonly HashSet supportedTypes = new HashSet { typeof(Tuple<>), typeof(Tuple<,>), typeof(Tuple<,,>), typeof(Tuple<,,,>), typeof(Tuple<,,,,>), typeof(Tuple<,,,,,>), typeof(Tuple<,,,,,,>), typeof(Tuple<,,,,,,,>) }; public override bool CanTransformType(Type type) { return type.IsGenericType && supportedTypes.Contains(type.GetGenericTypeDefinition()); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var type = value.GetType(); var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder(); for (int i = 1; i <= type.GetGenericArguments().Length; i++) { string name = string.Format("Item{0}", i); uIntArrayBox.AddValues(mapper.GetBoxId(type.GetProperty(name).GetValue(value))); } box.TypeId = mapper.GetBoxId(type); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build()); } public override object ToObject(Box box, Mapper mapper) { var type = (Type)mapper.GetObject(box.TypeId); var defaultValues = type.GetGenericArguments().Select(x => x.IsValueType ? Activator.CreateInstance(x) : null ).ToArray(); return Activator.CreateInstance(type, defaultValues); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var elements = uIntArrayBox.ValuesList.Select(mapper.GetObject).ToArray(); var type = obj.GetType(); for (int i = 1; i <= elements.Length; i++) { string name = string.Format("m_Item{0}", i); DataMemberAccessor.GenerateFieldSetter(type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance))(obj, elements[i - 1]); } } } #endregion #region Bitmap [Transformer("D0ADB806-2DFD-459D-B5DA-14B5F1152534", 222)] internal sealed class BitmapTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(Bitmap value) { lock (value) using (var ms = new MemoryStream()) { value.Save(ms, ImageFormat.Png); return ByteString.CopyFrom(ms.ToArray()); } } protected override Bitmap FromByteString(ByteString byteString) { using (var ms = new MemoryStream()) { ms.Write(byteString.ToArray(), 0, byteString.Length); ms.Seek(0, SeekOrigin.Begin); return new Bitmap(ms); } } } #endregion #region Font [Transformer("AFF27987-3301-4D70-9601-EFCA31BDA0DB", 223)] internal sealed class FontTransformer : UnsignedIntArrayBoxTransformer { protected override IEnumerable ToBoxType(Font value, Mapper mapper) { yield return mapper.GetStringId(GetFontFamilyName(value.FontFamily)); yield return mapper.GetBoxId(value.Size); yield return mapper.GetBoxId(value.Style); yield return mapper.GetBoxId(value.Unit); yield return mapper.GetBoxId(value.GdiCharSet); yield return mapper.GetBoxId(value.GdiVerticalFont); } protected override Font ToValueType(IEnumerable value, Type type, Mapper mapper) { var fontData = value.ToArray(); return new Font( GetFontFamily(mapper.GetString(fontData[0])), (float)mapper.GetObject(fontData[1]), (FontStyle)mapper.GetObject(fontData[2]), (GraphicsUnit)mapper.GetObject(fontData[3]), (byte)mapper.GetObject(fontData[4]), (bool)mapper.GetObject(fontData[5]) ); } public const string GENERIC_MONOSPACE_NAME = "_GenericMonospace"; public const string GENERIC_SANS_SERIF_NAME = "_GenericSansSerif"; public const string GENERIC_SERIF_NAME = "_GenericSerif"; public static FontFamily GetFontFamily(string name) { if (name == GENERIC_MONOSPACE_NAME) return FontFamily.GenericMonospace; if (name == GENERIC_SANS_SERIF_NAME) return FontFamily.GenericSansSerif; if (name == GENERIC_SERIF_NAME) return FontFamily.GenericSerif; return new FontFamily(name); } public static string GetFontFamilyName(FontFamily ff) { if (ff.Equals(FontFamily.GenericMonospace)) return GENERIC_MONOSPACE_NAME; if (ff.Equals(FontFamily.GenericSansSerif)) return GENERIC_SANS_SERIF_NAME; if (ff.Equals(FontFamily.GenericSerif)) return GENERIC_SERIF_NAME; return ff.Name; } } #endregion #region Array Types [Transformer("FF89F6D1-CDE3-498E-9166-F70AC6EB01F1", 301)] internal sealed class ByteArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(byte[] value) { return ByteString.CopyFrom(value); } protected override byte[] FromByteString(ByteString byteString) { return byteString.ToArray(); } } [Transformer("B49B3F2D-2E97-4BAB-8705-8D29DA707C6A", 302)] internal sealed class SByteArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(sbyte[] value) { return ByteString.CopyFrom(value.Select(b => (byte)b).ToArray()); } protected override sbyte[] FromByteString(ByteString byteString) { return byteString.Select(b => (sbyte)b).ToArray(); } } [Transformer("F25A73B2-6B67-4493-BD59-B836AF4455D1", 300)] internal sealed class BoolArrayTransformer : BoolArrayBoxTransformer { protected override IEnumerable ToBoxType(bool[] value, Mapper mapper) { return value; } protected override bool[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("2811FDD4-6800-4CBA-86D7-9071ED5775ED", 303)] internal sealed class ShortArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(short[] value) { var res = new byte[value.Length * 2]; for (int i = 0; i < value.Length; i++) { var bytes = BitConverter.GetBytes(value[i]); Array.Copy(bytes, 0, res, i * 2, 2); } return ByteString.CopyFrom(res); } protected override short[] FromByteString(ByteString byteString) { var bytes = byteString.ToArray(); var res = new short[bytes.Length / 2]; for (int i = 0; i < bytes.Length; i += 2) { res[i / 2] = BitConverter.ToInt16(bytes, i); } return res; } } [Transformer("1AAC2625-356C-40BC-8CB4-15CB3D047EB8", 304)] internal sealed class UShortArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(ushort[] value) { var res = new byte[value.Length * 2]; for (int i = 0; i < value.Length; i++) { var bytes = BitConverter.GetBytes(value[i]); Array.Copy(bytes, 0, res, i * 2, 2); } return ByteString.CopyFrom(res); } protected override ushort[] FromByteString(ByteString byteString) { var bytes = byteString.ToArray(); var res = new ushort[bytes.Length / 2]; for (int i = 0; i < bytes.Length; i += 2) { res[i / 2] = BitConverter.ToUInt16(bytes, i); } return res; } } [Transformer("12F19098-5D49-4C23-8897-69087F1C146D", 305)] internal sealed class CharArrayTransformer : ByteArrayBoxTransformer { protected override ByteString ToByteString(char[] value) { var res = new byte[value.Length * 2]; for (int i = 0; i < value.Length; i++) { var bytes = BitConverter.GetBytes(value[i]); Array.Copy(bytes, 0, res, i * 2, 2); } return ByteString.CopyFrom(res); } protected override char[] FromByteString(ByteString byteString) { var bytes = byteString.ToArray(); var res = new char[bytes.Length / 2]; for (int i = 0; i < bytes.Length; i += 2) { res[i / 2] = BitConverter.ToChar(bytes, i); } return res; } } [Transformer("5F6DC3BC-4433-4AE9-A636-4BD126F7DACD", 306)] internal sealed class IntArrayTransformer : IntArrayBoxTransformer { protected override IEnumerable ToBoxType(int[] value, Mapper mapper) { return value; } protected override int[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("3F10274F-D350-4C82-89EA-A5EB36D4EFCC", 307)] internal sealed class UIntArrayTransformer : UnsignedIntArrayBoxTransformer { protected override IEnumerable ToBoxType(uint[] value, Mapper mapper) { return value; } protected override uint[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("E9D550E2-57F7-47F3-803D-37A619DA1A5C", 308)] internal sealed class LongArrayTransformer : LongArrayBoxTransformer { protected override IEnumerable ToBoxType(long[] value, Mapper mapper) { return value; } protected override long[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("C02A205B-2176-4282-AC2B-ADEF96DDBE24", 309)] internal sealed class ULongArrayTransformer : UnsignedLongArrayBoxTransformer { protected override IEnumerable ToBoxType(ulong[] value, Mapper mapper) { return value; } protected override ulong[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("3C4590D9-C76E-4AFB-98FD-E50D3D051648", 310)] internal sealed class FloatArrayTransformer : FloatArrayBoxTransformer { protected override IEnumerable ToBoxType(float[] value, Mapper mapper) { return value; } protected override float[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("FB98C399-9323-4470-9A85-9186C2B2D5D4", 311)] internal sealed class DoubleArrayTransformer : DoubleArrayBoxTransformer { protected override IEnumerable ToBoxType(double[] value, Mapper mapper) { return value; } protected override double[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("68332513-9CF1-47FA-A093-6DDB663186EC", 312)] internal sealed class StringArrayTransformer : StringArrayBoxTransformer { protected override IEnumerable ToBoxType(string[] value, Mapper mapper) { return value; } protected override string[] ToValueType(IEnumerable value, Type type, Mapper mapper) { return value.ToArray(); } } [Transformer("B01ADF0A-ACAA-444E-9F82-0C7C2AF1F490", 400)] internal sealed class ArrayTransformer : Transformer { public override bool CanTransformType(Type type) { return type.IsArray; } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var type = value.GetType(); var array = (Array)value; var rank = array.Rank; var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder(); uIntArrayBox.AddValues(mapper.GetBoxId(rank)); int[] lengths = new int[rank]; int[] lowerBounds = new int[rank]; for (int i = 0; i < rank; i++) { lengths[i] = array.GetLength(i); lowerBounds[i] = array.GetLowerBound(i); } uIntArrayBox.AddRangeValues(lengths.Select(x => mapper.GetBoxId(x))); uIntArrayBox.AddRangeValues(lowerBounds.Select(x => mapper.GetBoxId(x))); int[] positions = (int[])lowerBounds.Clone(); while (positions[rank - 1] < lengths[rank - 1] + lowerBounds[rank - 1]) { uIntArrayBox.AddValues(mapper.GetBoxId(array.GetValue(positions))); positions[0] += 1; for (int i = 0; i < rank - 1; i++) { if (positions[i] >= lowerBounds[i] + lengths[i]) { positions[i] = lowerBounds[i]; positions[i + 1] += 1; } else { break; } } } box.TypeId = mapper.GetBoxId(type); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build()); } public override object ToObject(Box box, Mapper mapper) { var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var rank = (int)mapper.GetObject(uIntArrayBox.GetValues(0)); int[] lengths = new int[rank], lowerBounds = new int[rank]; for (int i = 0; i < rank; i++) lengths[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1)); for (int i = 0; i < rank; i++) lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1 + rank)); var type = (Type)mapper.GetObject(box.TypeId); return Array.CreateInstance(type.GetElementType(), lengths, lowerBounds); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var array = (Array)obj; var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var rank = (int)mapper.GetObject(uIntArrayBox.GetValues(0)); int[] lengths = new int[rank], lowerBounds = new int[rank]; for (int i = 0; i < rank; i++) lengths[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1)); for (int i = 0; i < rank; i++) lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.GetValues(i + 1 + rank)); int[] positions = (int[])lowerBounds.Clone(); var e = uIntArrayBox.ValuesList.Skip(1 + 2 * rank).GetEnumerator(); while (e.MoveNext()) { int[] currentPositions = positions; array.SetValue(mapper.GetObject(e.Current), currentPositions); positions[0] += 1; for (int i = 0; i < rank - 1; i++) { if (positions[i] >= lengths[i] + lowerBounds[i]) { positions[i] = lowerBounds[i]; positions[i + 1] += 1; } else { break; } } } } } #endregion [Transformer("4FA5EAAF-ECC7-4A9C-84E7-6583DA96F3B9", 500)] internal sealed class EnumerableTransformer : Transformer { private static readonly HashSet supportedTypes = new HashSet { typeof(Stack<>), typeof(Stack), typeof(Queue<>), typeof(Queue), typeof(HashSet<>), typeof(List<>), typeof(ArrayList) }; public override bool CanTransformType(Type type) { return type.IsGenericType && supportedTypes.Contains(type.GetGenericTypeDefinition()) || supportedTypes.Contains(type); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var uIntArrayBox = UnsignedIntArrayBox.CreateBuilder(); var type = value.GetType(); var propertyInfo = type.GetProperty("Comparer"); if (propertyInfo != null) { // TODO: where to store id for comparer box? (atm: first element in int array ...) var comparer = propertyInfo.GetValue(value); var comparerType = comparer.GetType(); if (Default.CompositeSerializers.Storable.StorableTypeAttribute.IsStorableType(comparerType)) uIntArrayBox.AddValues(mapper.GetBoxId(comparer)); else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any()) throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields"); else uIntArrayBox.AddValues(mapper.GetBoxId(comparerType)); } foreach (var item in (IEnumerable)value) uIntArrayBox.AddValues(mapper.GetBoxId(item)); box.TypeId = mapper.GetBoxId(type); box.SetExtension(UnsignedIntArrayBox.UnsignedIntArray, uIntArrayBox.Build()); } public override object ToObject(Box box, Mapper mapper) { var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var type = (Type)mapper.GetObject(box.TypeId); return Activator.CreateInstance(type); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var uIntArrayBox = box.GetExtension(UnsignedIntArrayBox.UnsignedIntArray); var elements = uIntArrayBox.ValuesList.Select(mapper.GetObject); var type = obj.GetType(); string methodName = string.Empty; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Stack<>) || type == typeof(Stack)) { elements = elements.Reverse(); methodName = "Push"; } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Queue<>) || type == typeof(Queue)) { methodName = "Enqueue"; } else { methodName = "Add"; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) { var fieldInfo = type.GetField("m_comparer", BindingFlags.NonPublic | BindingFlags.Instance); var comparerObj = mapper.GetObject(uIntArrayBox.GetValues(0)); var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj; fieldInfo.SetValue(obj, comparer); elements = elements.Skip(1); } } MethodInfo addMethod = type.GetMethod(methodName); foreach (var e in elements) addMethod.Invoke(obj, new[] { e }); } } [Transformer("C47A62F5-F113-4A43-A8EE-CF817EC799A2", 501)] internal sealed class DictionaryTransformer : Transformer { public override bool CanTransformType(Type type) { return type.IsGenericType && typeof(Dictionary<,>) == type.GetGenericTypeDefinition(); } public override Box ToBox(object o, Mapper mapper) { var box = Box.CreateBuilder(); box.TransformerId = mapper.GetTransformerId(this); Populate(box, o, mapper); return box.Build(); } private void Populate(Box.Builder box, object value, Mapper mapper) { var dictionaryBox = DictionaryBox.CreateBuilder(); foreach (DictionaryEntry item in (IDictionary)value) { dictionaryBox.AddKeyIds(mapper.GetBoxId(item.Key)); dictionaryBox.AddValueIds(mapper.GetBoxId(item.Value)); } var type = value.GetType(); var propertyInfo = type.GetProperty("Comparer"); var comparer = propertyInfo.GetValue(value); var comparerType = comparer.GetType(); if (Default.CompositeSerializers.Storable.StorableTypeAttribute.IsStorableType(comparerType)) dictionaryBox.SetComparerId(mapper.GetBoxId(comparer)); else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any()) throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields"); else dictionaryBox.SetComparerId(mapper.GetBoxId(comparerType)); box.TypeId = mapper.GetBoxId(type); box.SetExtension(DictionaryBox.Dictionary, dictionaryBox.Build()); } public override object ToObject(Box box, Mapper mapper) { var dictionaryBox = box.GetExtension(DictionaryBox.Dictionary); return Activator.CreateInstance((Type)mapper.GetObject(box.TypeId), dictionaryBox.ValueIdsCount); } public override void FillFromBox(object obj, Box box, Mapper mapper) { var type = obj.GetType(); var dictionaryBox = box.GetExtension(DictionaryBox.Dictionary); var comparerObj = mapper.GetObject(dictionaryBox.ComparerId); var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj; var fieldInfo = type.GetField("comparer", BindingFlags.NonPublic | BindingFlags.Instance); fieldInfo.SetValue(obj, comparer); var addMethod = type.GetMethod("Add"); for (int i = 0; i < dictionaryBox.KeyIdsCount; i++) { var key = mapper.GetObject(dictionaryBox.GetKeyIds(i)); var value = mapper.GetObject(dictionaryBox.GetValueIds(i)); addMethod.Invoke(obj, new[] { key, value }); } } } }