Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PersistenceReintegration/HeuristicLab.Persistence/4.0/Transformers/Transformers.cs @ 15509

Last change on this file since 15509 was 15509, checked in by jkarder, 6 years ago

#2520: worked on new persistence

  • changed message definitions
  • updated transformers
  • cleaned up
File size: 43.8 KB
RevLine 
[13326]1#region License Information
2/* HeuristicLab
[13358]3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[13326]4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
[14537]23using System.Collections;
[13367]24using System.Collections.Generic;
[13326]25using System.Drawing;
[14549]26using System.Drawing.Imaging;
27using System.Globalization;
28using System.IO;
[13367]29using System.Linq;
[14549]30using System.Reflection;
[15509]31using Google.Protobuf;
[13326]32
33namespace HeuristicLab.Persistence {
[14927]34  [StorableType("8c7e99f5-092f-4cef-8b72-8afec1d10236")]
[13358]35  public abstract class BoxTransformer<T> : Transformer {
[13326]36    public override bool CanTransformType(Type type) {
[13358]37      return type == typeof(T);
[13326]38    }
39
[13358]40    public override Box ToBox(object o, Mapper mapper) {
[15509]41      var box = new Box {
42        TransformerId = mapper.GetTransformerId(this),
43        TypeId = mapper.GetBoxId(o.GetType())
44      };
[13358]45      Populate(box, (T)o, mapper);
[15509]46      return box;
[13326]47    }
[15509]48
[13358]49    public override object ToObject(Box box, Mapper mapper) {
[14549]50      return Extract(box, (Type)mapper.GetObject(box.TypeId), mapper);
[13358]51    }
[15509]52
53    protected abstract void Populate(Box box, T value, Mapper mapper);
[13358]54    protected abstract T Extract(Box box, Type type, Mapper mapper);
[13326]55  }
56
[15509]57  [Transformer("854156DA-2A37-450F-92ED-355FBBD8D131", 50)]
58  [StorableType("D48991BB-1DDA-4D64-A2E6-5B5608F85F2A")]
[14549]59  internal sealed class TypeTransformer : Transformer {
60    public override bool CanTransformType(Type type) {
61      return typeof(Type).IsAssignableFrom(type);
62    }
[15509]63
[14549]64    public override Box ToBox(object o, Mapper mapper) {
[15509]65      var box = new Box {
66        TransformerId = mapper.GetTransformerId(this)
67      };
[14549]68      Populate(box, o, mapper);
[15509]69      return box;
[14549]70    }
[15509]71
72    private void Populate(Box box, object value, Mapper mapper) {
[14549]73      var type = (Type)value;
[15509]74      var typeBox = new TypeBox();
75
[14549]76      if (type.IsGenericType) {
77        box.TypeId = mapper.GetTypeId(type.GetGenericTypeDefinition());
[15509]78        typeBox.GenericTypeIds.AddRange(type.GetGenericArguments().Select(mapper.GetBoxId));
[14549]79      } else if (type.IsArray) {
80        box.TypeId = mapper.GetTypeId(typeof(Array));
[15509]81        typeBox.GenericTypeIds.Add(mapper.GetBoxId(type.GetElementType()));
[14549]82      } else {
83        box.TypeId = mapper.GetTypeId(type);
84      }
[14771]85
86      if (StorableTypeAttribute.IsStorableType(type))
87        typeBox.Version = StorableTypeAttribute.GetStorableTypeAttribute(type).Version;
[15509]88
89      box.BoxId = mapper.GetTypeBoxId(typeBox);
[14549]90    }
[15509]91
[14549]92    public override object ToObject(Box box, Mapper mapper) {
93      return Extract(box, mapper.GetType(box.TypeId), mapper);
94    }
[15509]95
[14549]96    private object Extract(Box box, Type type, Mapper mapper) {
[15509]97      var typeBox = mapper.GetTypeBox(box.BoxId);
98
[14549]99      if (type.IsGenericType) {
[15509]100        return type.MakeGenericType(typeBox.GenericTypeIds.Select(id => (Type)mapper.GetObject(id)).ToArray());
[14549]101      } else if (type == typeof(Array)) {
[15509]102        return ((Type)mapper.GetObject(typeBox.GenericTypeIds[0])).MakeArrayType();
[14549]103      } else {
[15509]104
[14549]105        return type;
106      }
107    }
108  }
109
[15509]110  [Transformer("4C610596-5234-4C49-998E-30007D64492E", 100)]
111  [StorableType("69870239-00B7-4C9D-AF0B-14208069FAC8")]
112  internal sealed class StringBoxTransformer : BoxTransformer<string> {
113    protected override void Populate(Box box, string value, Mapper mapper) { box.UInt = mapper.GetStringId(value); }
114    protected override string Extract(Box box, Type type, Mapper mapper) { return mapper.GetString(box.UInt); }
[14549]115  }
116
[15509]117  [Transformer("58E69402-2533-426A-B9B5-9F2EB5241560", 101)]
118  [StorableType("667182BB-D2D5-46C6-97CB-593CE1B19CBC")]
119  internal sealed class BoolBoxTransformer : BoxTransformer<bool> {
120    protected override void Populate(Box box, bool value, Mapper mapper) { box.Bool = value; }
121    protected override bool Extract(Box box, Type type, Mapper mapper) { return box.Bool; }
[13358]122  }
[13326]123
[15509]124  [Transformer("D78F3391-3CAE-4376-9348-7FB38A4DE0EB", 102)]
125  [StorableType("1E75D1D8-3FAD-4D68-86BB-95DE981FDDD2")]
126  internal sealed class IntBoxTransformer : BoxTransformer<int> {
127    protected override void Populate(Box box, int value, Mapper mapper) { box.Int = value; }
128    protected override int Extract(Box box, Type type, Mapper mapper) { return box.Int; }
[13358]129  }
[13326]130
[15509]131  [Transformer("25881263-F452-492E-9FD1-24E1938B048B", 103)]
132  [StorableType("7742A4A3-31B4-4449-9657-0D9F50F2382F")]
133  internal sealed class UIntBoxTransformer : BoxTransformer<uint> {
134    protected override void Populate(Box box, uint value, Mapper mapper) { box.UInt = value; }
135    protected override uint Extract(Box box, Type type, Mapper mapper) { return box.UInt; }
[13358]136  }
[13326]137
[15509]138  [Transformer("F4175165-382B-4B03-921E-5F923510FB1E", 104)]
139  [StorableType("985427E0-E4F0-4182-8D30-63DA7FB69735")]
140  internal sealed class LongBoxTransformer : BoxTransformer<long> {
141    protected override void Populate(Box box, long value, Mapper mapper) { box.Long = value; }
142    protected override long Extract(Box box, Type type, Mapper mapper) { return box.Long; }
[13358]143  }
[13326]144
[15509]145  [Transformer("E8F63973-3C0C-4FA9-B068-40EF4463B30B", 105)]
146  [StorableType("C9F95D84-BCDC-498E-A9AE-7187E483BBBA")]
147  internal sealed class ULongBoxTransformer : BoxTransformer<ulong> {
148    protected override void Populate(Box box, ulong value, Mapper mapper) { box.ULong = value; }
149    protected override ulong Extract(Box box, Type type, Mapper mapper) { return box.ULong; }
[13358]150  }
[13326]151
[15509]152  [Transformer("15489146-EA11-4B90-8020-AF5C10A2531C", 106)]
153  [StorableType("AF1C5176-859C-423B-A2BF-2AEA4D0792C7")]
154  internal sealed class FloatBoxTransformer : BoxTransformer<float> {
155    protected override void Populate(Box box, float value, Mapper mapper) { box.Float = value; }
156    protected override float Extract(Box box, Type type, Mapper mapper) { return box.Float; }
[13358]157  }
[13326]158
[15509]159  [Transformer("91FD51F3-9C47-4944-AC85-273ED0561E87", 107)]
160  [StorableType("4AB25AE9-2600-4041-8F31-C02CCE9A3BEC")]
161  internal sealed class DoubleBoxTransformer : BoxTransformer<double> {
162    protected override void Populate(Box box, double value, Mapper mapper) { box.Double = value; }
163    protected override double Extract(Box box, Type type, Mapper mapper) { return box.Double; }
[13358]164  }
[13326]165
[15509]166  [Transformer("BCB087EA-E477-47EB-9BCE-8C64BAC2F288", 108)]
167  [StorableType("341C2F99-8849-408E-99AA-7700FE0FB789")]
168  internal sealed class ByteBoxTransformer : BoxTransformer<byte> {
169    protected override void Populate(Box box, byte value, Mapper mapper) { box.UInt = value; }
170    protected override byte Extract(Box box, Type type, Mapper mapper) { return (byte)box.UInt; }
[13358]171  }
[13326]172
[15509]173  [Transformer("B90F61D9-75D0-4CAC-AF93-B8C6AB68F642", 109)]
174  [StorableType("FEC52DD5-A422-45C4-995F-09F3B0DEC13F")]
175  internal sealed class SByteBoxTransformer : BoxTransformer<sbyte> {
176    protected override void Populate(Box box, sbyte value, Mapper mapper) { box.Int = value; }
177    protected override sbyte Extract(Box box, Type type, Mapper mapper) { return (sbyte)box.Int; }
[13358]178  }
[13326]179
[15509]180  [Transformer("95EB44A4-EADD-4DA9-B60F-3262FAD6134B", 110)]
181  [StorableType("48744968-15F2-4B22-AAF2-6C0910239384")]
182  internal sealed class ShortBoxTransformer : BoxTransformer<short> {
183    protected override void Populate(Box box, short value, Mapper mapper) { box.Int = value; }
184    protected override short Extract(Box box, Type type, Mapper mapper) { return (short)box.Int; }
[13358]185  }
[13326]186
[15509]187  [Transformer("E3A33614-9120-400E-BAD9-2594F6804DA8", 111)]
188  [StorableType("DCF05BA3-3C57-4DBB-96B4-B2CE31CA60C5")]
189  internal sealed class UShortBoxTransformer : BoxTransformer<ushort> {
190    protected override void Populate(Box box, ushort value, Mapper mapper) { box.Int = value; }
191    protected override ushort Extract(Box box, Type type, Mapper mapper) { return (ushort)box.Int; }
[13358]192  }
[13326]193
[15509]194  [Transformer("C64EA534-E2E1-48F0-86C5-648AA02117BC", 112)]
195  [StorableType("142980B3-A251-48D2-BF02-A66C483D6385")]
196  internal sealed class CharBoxTransformer : BoxTransformer<char> {
197    protected override void Populate(Box box, char value, Mapper mapper) { box.UInt = value; }
198    protected override char Extract(Box box, Type type, Mapper mapper) { return (char)box.UInt; }
[13358]199  }
[13326]200
[15509]201  [Transformer("D50C4782-7211-4476-B50F-7D3378EE3E53", 200)]
202  [StorableType("4397B775-7D48-4C2A-8D28-ACC8C196CF70")]
203  internal sealed class StringArrayBoxTransformer : BoxTransformer<string[]> {
204    protected override void Populate(Box box, string[] value, Mapper mapper) {
205      var unsignedIntArrayBox = new UnsignedIntArrayBox();
206      unsignedIntArrayBox.Values.AddRange(value.Select(mapper.GetStringId));
207      box.BoxId = mapper.GetUnsignedIntArrayBoxId(unsignedIntArrayBox);
208    }
[13326]209
[15509]210    protected override string[] Extract(Box box, Type type, Mapper mapper) {
211      var unsignedIntArrayBox = mapper.GetUnsignedIntArrayBox(box.BoxId);
212      return unsignedIntArrayBox.Values.Select(mapper.GetString).ToArray();
213    }
[13358]214  }
[13387]215
[15509]216  [Transformer("C9CFA67B-DF13-4125-B781-98EC8F5E390F", 201)]
217  [StorableType("9719DB59-C6BC-4788-BBB0-389A1B49CFEE")]
218  internal sealed class BoolArrayBoxTransformer : BoxTransformer<bool[]> {
219    protected override void Populate(Box box, bool[] value, Mapper mapper) {
220      var boolArrayBox = new BoolArrayBox();
221      boolArrayBox.Values.AddRange(value);
222      box.BoxId = mapper.GetBoolArrayBoxId(boolArrayBox);
223    }
[13387]224
[15509]225    protected override bool[] Extract(Box box, Type type, Mapper mapper) {
226      var boolArrayBox = mapper.GetBoolArrayBox(box.BoxId);
227      return boolArrayBox.Values.ToArray();
[13387]228    }
229  }
[14549]230
[15509]231  [Transformer("BA2E18F6-5C17-40CA-A5B8-5690C5EFE872", 202)]
232  [StorableType("6548E9F0-621D-47BA-A605-8A47EF85C231")]
233  internal sealed class IntArrayBoxTransformer : BoxTransformer<int[]> {
234    protected override void Populate(Box box, int[] value, Mapper mapper) {
235      var intArrayBox = new IntArrayBox();
236      intArrayBox.Values.AddRange(value);
237      box.BoxId = mapper.GetIntArrayBoxId(intArrayBox);
[14549]238    }
[15509]239
240    protected override int[] Extract(Box box, Type type, Mapper mapper) {
241      var intArrayBox = mapper.GetIntArrayBox(box.BoxId);
242      return intArrayBox.Values.ToArray();
[14549]243    }
244  }
[13326]245
[15509]246  [Transformer("EEE7710D-86DE-47E1-887D-BDA2996B141E", 203)]
247  [StorableType("4127B466-AFC0-4050-8C45-1376A0E3E016")]
248  internal sealed class UnsignedIntArrayBoxTransformer : BoxTransformer<uint[]> {
249    protected override void Populate(Box box, uint[] value, Mapper mapper) {
250      var unsignedIntArrayBox = new UnsignedIntArrayBox();
251      unsignedIntArrayBox.Values.AddRange(value);
252      box.BoxId = mapper.GetUnsignedIntArrayBoxId(unsignedIntArrayBox);
253    }
[13326]254
[15509]255    protected override uint[] Extract(Box box, Type type, Mapper mapper) {
256      var unsignedIntArrayBox = mapper.GetUnsignedIntArrayBox(box.BoxId);
257      return unsignedIntArrayBox.Values.ToArray();
[13326]258    }
[15509]259  }
[13407]260
[15509]261  [Transformer("557932AA-F023-477F-AAD0-5098E8B8CD56", 204)]
262  [StorableType("C2ED50C8-C340-40C1-B00C-2F398EB709A0")]
263  internal sealed class LongArrayBoxTransformer : BoxTransformer<long[]> {
264    protected override void Populate(Box box, long[] value, Mapper mapper) {
265      var longArrayBox = new LongArrayBox();
266      longArrayBox.Values.AddRange(value);
267      box.BoxId = mapper.GetLongArrayBoxId(longArrayBox);
[13326]268    }
[13407]269
[15509]270    protected override long[] Extract(Box box, Type type, Mapper mapper) {
271      var longArrayBox = mapper.GetLongArrayBox(box.BoxId);
272      return longArrayBox.Values.ToArray();
[13386]273    }
[13326]274  }
275
[15509]276  [Transformer("CFF20DEE-2A55-4D04-B543-A4C7E0A8F7BF", 205)]
277  [StorableType("641AE353-5373-4811-BACB-C13D3144809C")]
278  internal sealed class UnsignedLongArrayBoxTransformer : BoxTransformer<ulong[]> {
279    protected override void Populate(Box box, ulong[] value, Mapper mapper) {
280      var unsignedLongArrayBox = new UnsignedLongArrayBox();
281      unsignedLongArrayBox.Values.AddRange(value);
282      box.BoxId = mapper.GetUnsignedLongArrayBoxId(unsignedLongArrayBox);
[14549]283    }
[15509]284
285    protected override ulong[] Extract(Box box, Type type, Mapper mapper) {
286      var unsignedLongArrayBox = mapper.GetUnsignedLongArrayBox(box.BoxId);
287      return unsignedLongArrayBox.Values.ToArray();
[14549]288    }
[15509]289  }
[13407]290
[15509]291  [Transformer("2A0F766D-FE71-4415-A75F-A32FB8BB9E2D", 206)]
292  [StorableType("AEE9384F-3857-4CE4-AE30-B99474F7A6C9")]
293  internal sealed class FloatArrayBoxTransformer : BoxTransformer<float[]> {
294    protected override void Populate(Box box, float[] value, Mapper mapper) {
295      var floatArrayBox = new FloatArrayBox();
296      floatArrayBox.Values.AddRange(value);
297      box.BoxId = mapper.GetFloatArrayBoxId(floatArrayBox);
[14549]298    }
299
[15509]300    protected override float[] Extract(Box box, Type type, Mapper mapper) {
301      var floatArrayBox = mapper.GetFloatArrayBox(box.BoxId);
302      return floatArrayBox.Values.ToArray();
[14549]303    }
304  }
305
[15509]306  [Transformer("192A8F7D-84C7-44BF-B0CA-AD387A241AAD", 207)]
307  [StorableType("17D0BA74-CB84-405C-8DBB-D9E361274A0A")]
308  internal sealed class DoubleArrayBoxTransformer : BoxTransformer<double[]> {
309    protected override void Populate(Box box, double[] value, Mapper mapper) {
310      var doubleArrayBox = new DoubleArrayBox();
311      doubleArrayBox.Values.AddRange(value);
312      box.BoxId = mapper.GetDoubleArrayBoxId(doubleArrayBox);
[14549]313    }
314
[15509]315    protected override double[] Extract(Box box, Type type, Mapper mapper) {
316      var doubleArrayBox = mapper.GetDoubleArrayBox(box.BoxId);
317      return doubleArrayBox.Values.ToArray();
[14549]318    }
319  }
320
[15509]321  [Transformer("3A35CECE-9953-4C29-A796-A56C02D80A05", 208)]
322  [StorableType("A076D11E-89AA-43C8-87F5-A0D0F52569EB")]
323  internal sealed class ByteArrayBoxTransformer : BoxTransformer<byte[]> {
324    protected override void Populate(Box box, byte[] value, Mapper mapper) {
325      box.Bytes = ByteString.CopyFrom(value);
[14549]326    }
327
[15509]328    protected override byte[] Extract(Box box, Type type, Mapper mapper) {
329      return box.Bytes.ToArray();
[14549]330    }
331  }
332
[15509]333  [Transformer("880D4A63-6C77-4F9F-8F7C-2D365F0AE829", 209)]
334  [StorableType("74F6FD4B-D7D7-43CD-B28B-3A775505FEE3")]
335  internal sealed class SByteArrayBoxTransformer : BoxTransformer<sbyte[]> {
336    protected override void Populate(Box box, sbyte[] value, Mapper mapper) {
337      box.Bytes = ByteString.CopyFrom(value.Select(x => (byte)x).ToArray());
[13407]338    }
339
[15509]340    protected override sbyte[] Extract(Box box, Type type, Mapper mapper) {
341      return box.Bytes.Select(x => (sbyte)x).ToArray();
[13407]342    }
[13326]343  }
[13367]344
[15509]345  [Transformer("9786E711-7C1D-4761-BD6B-445793834264", 210)]
346  [StorableType("5F32480E-AACB-4DB3-ADE3-1CF36E33C037")]
347  internal sealed class ShortArrayBoxTransformer : BoxTransformer<short[]> {
348    protected override void Populate(Box box, short[] value, Mapper mapper) {
[14537]349      var res = new byte[value.Length * 2];
350      for (int i = 0; i < value.Length; i++) {
351        var bytes = BitConverter.GetBytes(value[i]);
352        Array.Copy(bytes, 0, res, i * 2, 2);
353      }
[15509]354      box.Bytes = ByteString.CopyFrom(res);
[14537]355    }
[15509]356
357    protected override short[] Extract(Box box, Type type, Mapper mapper) {
358      var bytes = box.Bytes.ToArray();
[14537]359      var res = new short[bytes.Length / 2];
360      for (int i = 0; i < bytes.Length; i += 2) {
361        res[i / 2] = BitConverter.ToInt16(bytes, i);
362      }
363      return res;
364    }
[13375]365  }
366
[15509]367  [Transformer("1AAC2625-356C-40BC-8CB4-15CB3D047EB8", 211)]
368  [StorableType("C303B4CF-FFD0-47E2-9D94-07F2D558D17F")]
369  internal sealed class UShortArrayTransformer : BoxTransformer<ushort[]> {
370    protected override void Populate(Box box, ushort[] value, Mapper mapper) {
[14537]371      var res = new byte[value.Length * 2];
372      for (int i = 0; i < value.Length; i++) {
373        var bytes = BitConverter.GetBytes(value[i]);
374        Array.Copy(bytes, 0, res, i * 2, 2);
375      }
[15509]376      box.Bytes = ByteString.CopyFrom(res);
[14537]377    }
[15509]378
379    protected override ushort[] Extract(Box box, Type type, Mapper mapper) {
380      var bytes = box.Bytes.ToArray();
[14537]381      var res = new ushort[bytes.Length / 2];
382      for (int i = 0; i < bytes.Length; i += 2) {
383        res[i / 2] = BitConverter.ToUInt16(bytes, i);
384      }
385      return res;
386    }
[13375]387  }
388
[15509]389  [Transformer("12F19098-5D49-4C23-8897-69087F1C146D", 212)]
390  [StorableType("55F7C8B0-F2AA-4830-857D-6CE2807DA138")]
391  internal sealed class CharArrayTransformer : BoxTransformer<char[]> {
392    protected override void Populate(Box box, char[] value, Mapper mapper) {
[14537]393      var res = new byte[value.Length * 2];
394      for (int i = 0; i < value.Length; i++) {
395        var bytes = BitConverter.GetBytes(value[i]);
396        Array.Copy(bytes, 0, res, i * 2, 2);
397      }
[15509]398      box.Bytes = ByteString.CopyFrom(res);
[14537]399    }
[15509]400    protected override char[] Extract(Box box, Type type, Mapper mapper) {
401      var bytes = box.Bytes.ToArray();
[14537]402      var res = new char[bytes.Length / 2];
403      for (int i = 0; i < bytes.Length; i += 2) {
404        res[i / 2] = BitConverter.ToChar(bytes, i);
405      }
406      return res;
407    }
[13375]408  }
409
[15509]410  [Transformer("05AE4C5D-4D0C-47C7-B6D5-F04230C6F565", 301)]
411  [StorableType("A74820C8-F400-462A-913A-610BB588D04A")]
412  internal sealed class ArrayBoxTransformer : BoxTransformer<object> {
[13387]413    public override bool CanTransformType(Type type) {
414      return type.IsArray;
415    }
[15509]416
417    protected override void Populate(Box box, object value, Mapper mapper) {
[14594]418      var type = value.GetType();
[14549]419      var array = (Array)value;
[14594]420      var rank = array.Rank;
[14537]421
[15509]422      var uIntArrayBox = new UnsignedIntArrayBox();
423      uIntArrayBox.Values.Add(mapper.GetBoxId(rank));
[14537]424
[14594]425      int[] lengths = new int[rank];
426      int[] lowerBounds = new int[rank];
427      for (int i = 0; i < rank; i++) {
428        lengths[i] = array.GetLength(i);
429        lowerBounds[i] = array.GetLowerBound(i);
430      }
431
[15509]432      uIntArrayBox.Values.AddRange(lengths.Select(x => mapper.GetBoxId(x)));
433      uIntArrayBox.Values.AddRange(lowerBounds.Select(x => mapper.GetBoxId(x)));
[14594]434
435      int[] positions = (int[])lowerBounds.Clone();
436      while (positions[rank - 1] < lengths[rank - 1] + lowerBounds[rank - 1]) {
[15509]437        uIntArrayBox.Values.Add(mapper.GetBoxId(array.GetValue(positions)));
[14594]438        positions[0] += 1;
439        for (int i = 0; i < rank - 1; i++) {
440          if (positions[i] >= lowerBounds[i] + lengths[i]) {
441            positions[i] = lowerBounds[i];
442            positions[i + 1] += 1;
443          } else {
444            break;
445          }
446        }
447      }
448
[15509]449      box.BoxId = mapper.GetUnsignedIntArrayBoxId(uIntArrayBox);
[14537]450    }
[14594]451
[15509]452    protected override object Extract(Box box, Type type, Mapper mapper) {
453      var uIntArrayBox = mapper.GetUnsignedIntArrayBox(box.BoxId);
454      var rank = (int)mapper.GetObject(uIntArrayBox.Values[0]);
455
[14594]456      int[] lengths = new int[rank], lowerBounds = new int[rank];
457      for (int i = 0; i < rank; i++)
[15509]458        lengths[i] = (int)mapper.GetObject(uIntArrayBox.Values[i + 1]);
[14594]459      for (int i = 0; i < rank; i++)
[15509]460        lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.Values[i + 1 + rank]);
[14594]461
462      return Array.CreateInstance(type.GetElementType(), lengths, lowerBounds);
[14537]463    }
[15509]464
[14549]465    public override void FillFromBox(object obj, Box box, Mapper mapper) {
[14594]466      var array = (Array)obj;
[15509]467      var uIntArrayBox = mapper.GetUnsignedIntArrayBox(box.BoxId);
468      var rank = (int)mapper.GetObject(uIntArrayBox.Values[0]);
[14594]469
470      int[] lengths = new int[rank], lowerBounds = new int[rank];
471      for (int i = 0; i < rank; i++)
[15509]472        lengths[i] = (int)mapper.GetObject(uIntArrayBox.Values[i + 1]);
[14594]473      for (int i = 0; i < rank; i++)
[15509]474        lowerBounds[i] = (int)mapper.GetObject(uIntArrayBox.Values[i + 1 + rank]);
[14594]475
476      int[] positions = (int[])lowerBounds.Clone();
[15509]477      var e = uIntArrayBox.Values.Skip(1 + 2 * rank).GetEnumerator();
[14594]478      while (e.MoveNext()) {
479        int[] currentPositions = positions;
480        array.SetValue(mapper.GetObject(e.Current), currentPositions);
481        positions[0] += 1;
482        for (int i = 0; i < rank - 1; i++) {
483          if (positions[i] >= lengths[i] + lowerBounds[i]) {
484            positions[i] = lowerBounds[i];
485            positions[i + 1] += 1;
486          } else {
487            break;
488          }
489        }
490      }
[14537]491    }
492  }
493
[15509]494  [Transformer("26AD5F85-1D77-4579-BCB9-CD409B48AC7A", 302)]
495  [StorableType("A96E2C1E-EBDF-4D81-A0ED-91677BC84FEE")]
496  internal sealed class EnumerableBoxTransformer : BoxTransformer<object> {
[14549]497    private static readonly HashSet<Type> supportedTypes = new HashSet<Type> {
498      typeof(Stack<>), typeof(Stack),
499      typeof(Queue<>), typeof(Queue),
500      typeof(HashSet<>),
501      typeof(List<>), typeof(ArrayList)
502    };
[15509]503
[14537]504    public override bool CanTransformType(Type type) {
[14549]505      return type.IsGenericType && supportedTypes.Contains(type.GetGenericTypeDefinition()) || supportedTypes.Contains(type);
[14537]506    }
[14594]507
[15509]508    protected override void Populate(Box box, object value, Mapper mapper) {
509      var uIntArrayBox = new UnsignedIntArrayBox();
510
[14594]511      var type = value.GetType();
512      var propertyInfo = type.GetProperty("Comparer");
513      if (propertyInfo != null) {
514        // TODO: where to store id for comparer box? (atm: first element in int array ...)
515        var comparer = propertyInfo.GetValue(value);
516        var comparerType = comparer.GetType();
[14927]517        if (StorableTypeAttribute.IsStorableType(comparerType))
[15509]518          uIntArrayBox.Values.Add(mapper.GetBoxId(comparer));
[14594]519        else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any())
520          throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields");
521        else
[15509]522          uIntArrayBox.Values.Add(mapper.GetBoxId(comparerType));
[14594]523      }
524
[14549]525      foreach (var item in (IEnumerable)value)
[15509]526        uIntArrayBox.Values.Add(mapper.GetBoxId(item));
[14594]527
[15509]528      box.BoxId = mapper.GetUnsignedIntArrayBoxId(uIntArrayBox);
[14537]529    }
[15509]530
531    protected override object Extract(Box box, Type type, Mapper mapper) {
[14594]532      return Activator.CreateInstance(type);
[14549]533    }
[15509]534
[14549]535    public override void FillFromBox(object obj, Box box, Mapper mapper) {
[15509]536      var uIntArrayBox = mapper.GetUnsignedIntArrayBox(box.BoxId);
537      var elements = uIntArrayBox.Values.Select(mapper.GetObject);
[14549]538      var type = obj.GetType();
[14594]539
[14549]540      string methodName = string.Empty;
541      if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Stack<>) || type == typeof(Stack)) {
542        elements = elements.Reverse();
543        methodName = "Push";
544      } else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Queue<>) || type == typeof(Queue)) {
545        methodName = "Enqueue";
[14537]546      } else {
[14549]547        methodName = "Add";
[14594]548        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(HashSet<>)) {
549          var fieldInfo = type.GetField("m_comparer", BindingFlags.NonPublic | BindingFlags.Instance);
[15509]550          var comparerObj = mapper.GetObject(uIntArrayBox.Values[0]);
[14594]551          var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj;
552          fieldInfo.SetValue(obj, comparer);
553          elements = elements.Skip(1);
554        }
[14537]555      }
[14549]556
557      MethodInfo addMethod = type.GetMethod(methodName);
558      foreach (var e in elements)
559        addMethod.Invoke(obj, new[] { e });
[14537]560    }
561  }
562
[15509]563  [Transformer("C47A62F5-F113-4A43-A8EE-CF817EC799A2", 303)]
564  [StorableType("BA53DF84-DC97-4D8D-A493-868972ED1002")]
565  internal sealed class DictionaryTransformer : BoxTransformer<object> {
[14537]566    public override bool CanTransformType(Type type) {
[14549]567      return type.IsGenericType && typeof(Dictionary<,>) == type.GetGenericTypeDefinition();
[14537]568    }
[15509]569
570    protected override void Populate(Box box, object value, Mapper mapper) {
571      var dictionaryBox = new DictionaryBox();
[14537]572      foreach (DictionaryEntry item in (IDictionary)value) {
[15509]573        dictionaryBox.KeyValuePairs.Add(mapper.GetBoxId(item.Key), mapper.GetBoxId(item.Value));
[14537]574      }
[14549]575
576      var type = value.GetType();
577      var propertyInfo = type.GetProperty("Comparer");
578      var comparer = propertyInfo.GetValue(value);
579
[14594]580      var comparerType = comparer.GetType();
[14927]581      if (StorableTypeAttribute.IsStorableType(comparerType))
[15509]582        dictionaryBox.ComparerId = mapper.GetBoxId(comparer);
[14594]583      else if (comparerType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Any())
584        throw new NotSupportedException("Cannot serialize non-storable equality comparers with fields");
585      else
[15509]586        dictionaryBox.ComparerId = mapper.GetBoxId(comparerType);
[14594]587
[15509]588      box.BoxId = mapper.GetDictionaryBoxId(dictionaryBox);
[14537]589    }
[15509]590
591    protected override object Extract(Box box, Type type, Mapper mapper) {
592      var dictionaryBox = mapper.GetDictionaryBox(box.BoxId);
593      return Activator.CreateInstance(type, dictionaryBox.KeyValuePairs.Count);
[14537]594    }
[15509]595
[14549]596    public override void FillFromBox(object obj, Box box, Mapper mapper) {
597      var type = obj.GetType();
[15509]598      var dictionaryBox = mapper.GetDictionaryBox(box.BoxId);
[14594]599      var comparerObj = mapper.GetObject(dictionaryBox.ComparerId);
600      var comparer = comparerObj is Type ? Activator.CreateInstance((Type)comparerObj) : comparerObj;
601
602      var fieldInfo = type.GetField("comparer", BindingFlags.NonPublic | BindingFlags.Instance);
603      fieldInfo.SetValue(obj, comparer);
604
[14549]605      var addMethod = type.GetMethod("Add");
[15509]606      foreach (var entry in dictionaryBox.KeyValuePairs) {
607        var key = mapper.GetObject(entry.Key);
608        var value = mapper.GetObject(entry.Value);
[14549]609        addMethod.Invoke(obj, new[] { key, value });
610      }
611    }
[15509]612
613    [Transformer("93FF076B-BC4B-4C39-8C40-15E004468C98", 219)]
614    [StorableType("F8A7DBB4-E1CE-4DB8-905E-F3A05F5CA000")]
615    internal sealed class EnumTransformer : Transformer {
616      public override bool CanTransformType(Type type) {
617        return typeof(Enum).IsAssignableFrom(type);
618      }
619
620      public override Box ToBox(object o, Mapper mapper) {
621        var box = new Box {
622          TransformerId = mapper.GetTransformerId(this),
623          TypeId = mapper.GetStringId(o.GetType().AssemblyQualifiedName),
624          UInt = mapper.GetStringId(Enum.Format(o.GetType(), o, "G")),
625        };
626        return box;
627      }
628
629      public override object ToObject(Box box, Mapper mapper) {
630        return Enum.Parse(Type.GetType(mapper.GetString(box.TypeId)), mapper.GetString(box.UInt));
631      }
632    }
633
634    [Transformer("268617FE-3F0F-4029-8248-EDA420901FB6", 10000)]
635    [StorableType("320CBA58-1AAF-492B-BE3B-F59EEA085EBE")]
636    internal sealed class ObjectBoxTransformer : BoxTransformer<object> {
637      protected override void Populate(Box box, object value, Mapper mapper) { }
638      protected override object Extract(Box box, Type type, Mapper mapper) { return new object(); }
639    }
[14537]640  }
[15509]641
642  [Transformer("90F9F16D-9F94-491B-AC3B-E1C6F3432127", 400)]
643  [StorableType("C3C23FEE-DB96-4CEA-A38B-6BB73811F877")]
644  internal sealed class DecimalBoxTransformer : BoxTransformer<decimal> {
645    protected override decimal Extract(Box box, Type type, Mapper mapper) {
646      return ParseG30(mapper.GetString(box.UInt));
647    }
648
649    protected override void Populate(Box box, decimal value, Mapper mapper) {
650      box.UInt = mapper.GetStringId(FormatG30(value));
651    }
652
653    private static decimal ParseG30(string s) {
654      decimal d;
655      if (decimal.TryParse(s,
656        NumberStyles.AllowDecimalPoint |
657        NumberStyles.AllowExponent |
658        NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out d))
659        return d;
660      throw new FormatException(
661        string.Format("Invalid decimal G30 number format \"{0}\" could not be parsed", s));
662    }
663
664    private static string FormatG30(decimal d) {
665      return d.ToString("g30", CultureInfo.InvariantCulture);
666    }
667  }
668
669  [Transformer("1C6C350F-B2C8-40F0-A964-54DDB0D087A3", 401)]
670  [StorableType("9D99D155-E3BB-40CE-AF64-6E153D876148")]
671  internal sealed class DateTimeBoxTransformer : BoxTransformer<DateTime> {
672    protected override void Populate(Box box, DateTime value, Mapper mapper) {
673      box.Long = value.Ticks;
674    }
675
676    protected override DateTime Extract(Box box, Type type, Mapper mapper) {
677      return new DateTime(box.Long);
678    }
679  }
680
681  [Transformer("964074C9-4B82-4725-97AF-612A193EA5C6", 402)]
682  [StorableType("9CA7C1F7-784C-48D5-A6F4-E1FD7B3A2FEC")]
683  internal sealed class TimeSpanBoxTransformer : BoxTransformer<TimeSpan> {
684    protected override void Populate(Box box, TimeSpan value, Mapper mapper) {
685      box.Long = value.Ticks;
686    }
687
688    protected override TimeSpan Extract(Box box, Type type, Mapper mapper) {
689      return new TimeSpan(box.Long);
690    }
691  }
692
693  [Transformer("B0C0165B-6279-4CC3-8DB7-D36898BFBC38", 403)]
694  [StorableType("ED6B7AE1-CE2B-4891-9BF3-72F5D1D67D93")]
695  internal sealed class PointTransformer : BoxTransformer<Point> {
696    protected override void Populate(Box box, Point value, Mapper mapper) {
697      var intArrayBox = new IntArrayBox();
698      intArrayBox.Values.AddRange(new[] { value.X, value.Y });
699      box.BoxId = mapper.GetIntArrayBoxId(intArrayBox);
700    }
701
702    protected override Point Extract(Box box, Type type, Mapper mapper) {
703      var intArrayBox = mapper.GetIntArrayBox(box.BoxId);
704      return new Point(intArrayBox.Values[0], intArrayBox.Values[1]);
705    }
706  }
707
708  [Transformer("D0ADB806-2DFD-459D-B5DA-14B5F1152534", 404)]
709  [StorableType("B13D6153-E71D-4B76-9893-81D3570403E8")]
710  internal sealed class BitmapTransformer : BoxTransformer<Bitmap> {
711    protected override void Populate(Box box, Bitmap value, Mapper mapper) {
712      lock (value)
713        using (var ms = new MemoryStream()) {
714          value.Save(ms, ImageFormat.Png);
715          box.Bytes = ByteString.CopyFrom(ms.ToArray());
716        }
717    }
718
719    protected override Bitmap Extract(Box box, Type type, Mapper mapper) {
720      using (var ms = new MemoryStream()) {
721        ms.Write(box.Bytes.ToArray(), 0, box.Bytes.Length);
722        ms.Seek(0, SeekOrigin.Begin);
723        return new Bitmap(ms);
724      }
725    }
726  }
727
728  [Transformer("AFF27987-3301-4D70-9601-EFCA31BDA0DB", 405)]
729  [StorableType("B9F9A371-4DCB-478B-B0D4-6F87A15C02B5")]
730  internal sealed class FontTransformer : BoxTransformer<Font> {
731    protected override void Populate(Box box, Font value, Mapper mapper) {
732      var unsignedIntArrayBox = new UnsignedIntArrayBox();
733      unsignedIntArrayBox.Values.Add(mapper.GetStringId(GetFontFamilyName(value.FontFamily)));
734      unsignedIntArrayBox.Values.Add(mapper.GetBoxId(value.Size));
735      unsignedIntArrayBox.Values.Add(mapper.GetBoxId(value.Style));
736      unsignedIntArrayBox.Values.Add(mapper.GetBoxId(value.Unit));
737      unsignedIntArrayBox.Values.Add(mapper.GetBoxId(value.GdiCharSet));
738      unsignedIntArrayBox.Values.Add(mapper.GetBoxId(value.GdiVerticalFont));
739      box.BoxId = mapper.GetUnsignedIntArrayBoxId(unsignedIntArrayBox);
740    }
741
742    protected override Font Extract(Box box, Type type, Mapper mapper) {
743      var value = mapper.GetUnsignedIntArrayBox(box.BoxId);
744      var fontData = value.Values;
745      return new Font(
746        GetFontFamily(mapper.GetString(fontData[0])),
747        (float)mapper.GetObject(fontData[1]),
748        (FontStyle)mapper.GetObject(fontData[2]),
749        (GraphicsUnit)mapper.GetObject(fontData[3]),
750        (byte)mapper.GetObject(fontData[4]),
751        (bool)mapper.GetObject(fontData[5])
752      );
753    }
754
755    public const string GENERIC_MONOSPACE_NAME = "_GenericMonospace";
756    public const string GENERIC_SANS_SERIF_NAME = "_GenericSansSerif";
757    public const string GENERIC_SERIF_NAME = "_GenericSerif";
758
759    public static FontFamily GetFontFamily(string name) {
760      if (name == GENERIC_MONOSPACE_NAME) return FontFamily.GenericMonospace;
761      if (name == GENERIC_SANS_SERIF_NAME) return FontFamily.GenericSansSerif;
762      if (name == GENERIC_SERIF_NAME) return FontFamily.GenericSerif;
763      return new FontFamily(name);
764    }
765
766    public static string GetFontFamilyName(FontFamily ff) {
767      if (ff.Equals(FontFamily.GenericMonospace)) return GENERIC_MONOSPACE_NAME;
768      if (ff.Equals(FontFamily.GenericSansSerif)) return GENERIC_SANS_SERIF_NAME;
769      if (ff.Equals(FontFamily.GenericSerif)) return GENERIC_SERIF_NAME;
770      return ff.Name;
771    }
772  }
773
774  [Transformer("D912D573-CE41-40B8-8F95-646C183662F6", 406)]
775  [StorableType("3ED2C12F-BE41-45F5-AA0A-C2F23EB99FBD")]
776  internal sealed class KeyValuePairBoxTransformer : BoxTransformer<object> {
777    public override bool CanTransformType(Type type) {
778      return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>));
779    }
780
781    protected override void Populate(Box box, object value, Mapper mapper) {
782      var unsignedIntArrayBox = new UnsignedIntArrayBox();
783      var type = value.GetType();
784      var pair = new uint[2];
785      pair[0] = mapper.GetBoxId(type.GetProperty("Key").GetValue(value));
786      pair[1] = mapper.GetBoxId(type.GetProperty("Value").GetValue(value));
787      unsignedIntArrayBox.Values.AddRange(pair);
788      box.BoxId = mapper.GetUnsignedIntArrayBoxId(unsignedIntArrayBox);
789    }
790
791    public override void FillFromBox(object obj, Box box, Mapper mapper) {
792      var b = mapper.GetUnsignedIntArrayBox(box.BoxId);
793      var key = mapper.GetObject(b.Values[0]);
794      var val = mapper.GetObject(b.Values[1]);
795      var type = obj.GetType();
796      //DataMemberAccessor.GenerateFieldSetter(type.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance))(obj, key);
797      //DataMemberAccessor.GenerateFieldSetter(type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance))(obj, val);
798      type.GetField("key", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, key);
799      type.GetField("value", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj, val);
800    }
801
802    protected override object Extract(Box box, Type type, Mapper mapper) {
803      return Activator.CreateInstance(type);
804    }
805  }
806
807  [Transformer("BBA08D33-FDA4-4EB6-8D94-9BF3D30C3E11", 407)]
808  [StorableType("B0333A12-7D91-47A5-ACD4-49E43E5A18DC")]
809  internal sealed class TupleBoxTransformer : BoxTransformer<object> {
810    private static readonly HashSet<Type> supportedTypes = new HashSet<Type> {
811      typeof(Tuple<>), typeof(Tuple<,>), typeof(Tuple<,,>), typeof(Tuple<,,,>),
812      typeof(Tuple<,,,,>), typeof(Tuple<,,,,,>), typeof(Tuple<,,,,,,>), typeof(Tuple<,,,,,,,>)
813    };
814
815    public override bool CanTransformType(Type type) {
816      return type.IsGenericType && supportedTypes.Contains(type.GetGenericTypeDefinition());
817    }
818
819    protected override void Populate(Box box, object value, Mapper mapper) {
820      var type = value.GetType();
821      var uIntArrayBox = new UnsignedIntArrayBox();
822      for (int i = 1; i <= type.GetGenericArguments().Length; i++) {
823        string name = string.Format("Item{0}", i);
824        uIntArrayBox.Values.Add(mapper.GetBoxId(type.GetProperty(name).GetValue(value)));
825      }
826      box.BoxId = mapper.GetUnsignedIntArrayBoxId(uIntArrayBox);
827    }
828
829    protected override object Extract(Box box, Type type, Mapper mapper) {
830      var defaultValues = type.GetGenericArguments().Select(x =>
831        x.IsValueType ? Activator.CreateInstance(x) : null
832      ).ToArray();
833      return Activator.CreateInstance(type, defaultValues);
834    }
835
836    public override void FillFromBox(object obj, Box box, Mapper mapper) {
837      var uIntArrayBox = mapper.GetUnsignedIntArrayBox(box.BoxId);
838      var elements = uIntArrayBox.Values.Select(mapper.GetObject).ToArray();
839      var type = obj.GetType();
840      for (int i = 1; i <= elements.Length; i++) {
841        string name = string.Format("m_Item{0}", i);
842        DataMemberAccessor.GenerateFieldSetter(type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance))(obj, elements[i - 1]);
843      }
844    }
845  }
846
847  [Transformer("731F9A18-6BF4-43BE-95CF-8205552C9B70", 500)]
848  [StorableType("73FCDE79-436D-476E-B2EA-A7A1A4A810B5")]
849  internal sealed class StructBoxTransformer : BoxTransformer<object> {
850    public override bool CanTransformType(Type type) {
851      return type.IsValueType && !type.IsPrimitive && !type.IsEnum && type.IsSealed;
852    }
853
854    protected override void Populate(Box box, object value, Mapper mapper) {
855      var b = new StorableClassBox();
856      var type = value.GetType();
857
858      var components = new Dictionary<uint, uint>();
859      foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
860        var component = mapper.GetBoxId(fieldInfo.GetValue(value));
861        components.Add(mapper.GetStringId(fieldInfo.Name), component);
862      }
863
864      foreach (var component in components) {
865        b.KeyValuePairs.Add(component.Key, component.Value);
866      }
867
868      box.BoxId = mapper.GetStorableClassBoxId(b);
869    }
870
871    protected override object Extract(Box box, Type type, Mapper mapper) {
872      var data = mapper.GetStorableClassBox(box.BoxId);
873      var obj = Activator.CreateInstance(type);
874
875      var components = new Dictionary<uint, uint>();
876      foreach (var kvp in data.KeyValuePairs) {
877        components.Add(kvp.Key, kvp.Value);
878      }
879
880      foreach (var t in components) {
881        string name = mapper.GetString(t.Key);
882        MemberInfo[] mis = type.GetMember(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
883        if (mis.Length != 1)
884          throw new Exception("ambiguous struct member name " + name);
885        MemberInfo mi = mis[0];
886        if (StorableAttribute.IsStorable(mi))
887          throw new PersistenceException("Don't use stroable attributes for structs as all fields are serialized automatically.");
888        if (mi.MemberType == MemberTypes.Field)
889          ((FieldInfo)mi).SetValue(obj, mapper.GetObject(t.Value));
890        else
891          throw new Exception("invalid struct member type " + mi.MemberType.ToString());
892      }
893
894      return obj;
895    }
896
897  }
898
899  [Transformer("78556C88-0FEE-4602-95C7-A469B2DDB468", 600)]
900  [StorableType("3A578289-43CA-40F8-9F1E-2BDD255CB8FB")]
901  internal sealed class StorableTypeBoxTransformer : BoxTransformer<object> {
902    public override bool CanTransformType(Type type) {
903      return StorableTypeAttribute.IsStorableType(type) && !type.IsValueType && !type.IsEnum || // don't transform structs or enums
904        type.BaseType != null && CanTransformType(type.BaseType);
905    }
906
907    protected override void Populate(Box box, object value, Mapper mapper) {
908      var b = new StorableClassBox();
909      var type = value.GetType();
910      var typeInfo = Mapper.StaticCache.GetTypeInfo(type);
911
912      var emptyArgs = new object[0];
913      foreach (var hook in typeInfo.BeforeSerializationHooks) {
914        hook.Invoke(value, emptyArgs);
915      }
916
917      var components = new Dictionary<uint, uint>();
918      foreach (var componentInfo in typeInfo.Fields) {
919        var field = (FieldInfo)componentInfo.MemberInfo;
920        var component = mapper.GetBoxId(field.GetValue(value));
921        components.Add(mapper.GetStringId(componentInfo.Name), component);
922      }
923
924      foreach (var componentInfo in typeInfo.Properties.Where(x => x.Readable)) {
925        var property = (PropertyInfo)componentInfo.MemberInfo;
926        var component = mapper.GetBoxId(property.GetValue(value, null));
927        components.Add(mapper.GetStringId(componentInfo.Name), component);
928      }
929
930      foreach (var component in components) {
931        b.KeyValuePairs.Add(component.Key, component.Value);
932      }
933
934      box.BoxId = mapper.GetStorableClassBoxId(b);
935    }
936
937    protected override object Extract(Box box, Type type, Mapper mapper) {
938      return mapper.CreateInstance(type);
939    }
940
941    public override void FillFromBox(object obj, Box box, Mapper mapper) {
942      var data = mapper.GetStorableClassBox(box.BoxId);
943      var type = obj.GetType();
944      var typeInfo = Mapper.StaticCache.GetTypeInfo(type);
945      var typeBox = mapper.GetTypeBox(mapper.GetBox(box.TypeId).BoxId);
946      var version = Math.Max(typeBox.Version, 1);
947      var typeGuid = typeInfo.StorableTypeAttribute.Guid;
948
949      var components = new Dictionary<uint, uint>();
950      foreach (var kvp in data.KeyValuePairs) {
951        components.Add(kvp.Key, kvp.Value);
952      }
953
954      var conversionMethods =
955        type.Assembly.GetTypes().SelectMany(t =>
956          t.GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
957          .Where(StorableConversionAttribute.IsStorableConversionMethod)
958          .Where(mi => StorableConversionAttribute.GetGuid(mi) == typeGuid &&
959                       StorableConversionAttribute.GetVersion(mi) >= version))
960          .OrderBy(StorableConversionAttribute.GetVersion)
961          .ToArray();
962
963      // put all objects into dictionary for conversion
964      var dict = new Dictionary<string, object>();
965      foreach (var component in components) {
966        dict.Add(mapper.GetString(component.Key), mapper.GetObject(component.Value));
967      }
968
969      Dictionary<string, object> lastDict = new Dictionary<string, object>();
970      foreach (var convMeth in conversionMethods) {
971        if (StorableConversionAttribute.GetVersion(convMeth) != version)
972          throw new PersistenceException(string.Format("No conversion method defined for type {0} version {1}", typeGuid, version));
973        lastDict = (Dictionary<string, object>)convMeth.Invoke(null, new object[] { dict });
974        foreach (var kvp in lastDict) {
975          dict[kvp.Key] = kvp.Value;
976        }
977        version++;
978      }
979      if (version != typeInfo.StorableTypeAttribute.Version)
980        throw new PersistenceException(string.Format("Missing one or more conversion methods for type {0} version {1}",
981          typeGuid, typeInfo.StorableTypeAttribute.Version));
982
983      // set default values for all fields and properties
984      foreach (var componentInfo in typeInfo.Fields) {
985        var field = (FieldInfo)componentInfo.MemberInfo;
986        if (componentInfo.StorableAttribute != null && componentInfo.StorableAttribute.DefaultValue != null)
987          field.SetValue(obj, componentInfo.StorableAttribute.DefaultValue);
988      }
989      foreach (var componentInfo in typeInfo.Properties.Where(x => x.Writeable)) {
990        var property = (PropertyInfo)componentInfo.MemberInfo;
991        if (componentInfo.StorableAttribute != null && componentInfo.StorableAttribute.DefaultValue != null)
992          property.SetValue(obj, componentInfo.StorableAttribute.DefaultValue, null);
993      }
994
995      // set all members as generated by conversion method chain
996      foreach (var kvp in dict) {
997        var key = kvp.Key;
998        var val = kvp.Value;
999        var fieldInfo = typeInfo.Fields.FirstOrDefault(fi => fi.Name == key);
1000        if (fieldInfo != null) {
1001          var field = (FieldInfo)fieldInfo.MemberInfo;
1002          field.SetValue(obj, val);
1003          lastDict.Remove(fieldInfo.Name); // only for consistency check
1004          continue;
1005        }
1006        var propInfo = typeInfo.Properties.Where(x => x.Writeable).FirstOrDefault(pi => pi.Name == key);
1007        if (propInfo != null) {
1008          var prop = (PropertyInfo)propInfo.MemberInfo;
1009          prop.SetValue(obj, val, null);
1010          lastDict.Remove(propInfo.Name);    // only for consistency check
1011          continue;
1012        }
1013      }
1014
1015      if (lastDict.Any())
1016        throw new PersistenceException(string.Format("Invalid conversion method. The following members are undefined in type {0} version {1}: {2}",
1017          typeGuid, typeInfo.StorableTypeAttribute.Version,
1018          string.Join(", ", lastDict.Keys)));
1019
1020      var emptyArgs = new object[0];
1021      foreach (var hook in typeInfo.AfterDeserializationHooks) {
1022        hook.Invoke(obj, emptyArgs);
1023      }
1024    }
1025  }
[13326]1026}
Note: See TracBrowser for help on using the repository browser.