disable broken tests on net_4_0
[mcs.git] / class / corlib / System.Runtime.Serialization.Formatters.Binary / ObjectReader.cs
blob8dbe14da3770b771f78887ec3fe79c08e64ce173
1 // ObjectReader.cs
2 //
3 // Author:
4 // Lluis Sanchez Gual (lluis@ideary.com)
5 // Patrik Torstensson
6 //
7 // (C) 2003 Lluis Sanchez Gual
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System;
33 using System.Runtime.Serialization;
34 using System.IO;
35 using System.Collections;
36 using System.Reflection;
37 using System.Runtime.Remoting.Messaging;
38 using System.Globalization;
40 namespace System.Runtime.Serialization.Formatters.Binary
42 internal class ObjectReader
44 // BinaryFormatter _formatter;
45 ISurrogateSelector _surrogateSelector;
46 StreamingContext _context;
47 SerializationBinder _binder;
49 #if NET_1_1
50 TypeFilterLevel _filterLevel;
51 #endif
53 ObjectManager _manager;
54 Hashtable _registeredAssemblies = new Hashtable();
55 Hashtable _typeMetadataCache = new Hashtable();
57 object _lastObject = null;
58 long _lastObjectID = 0;
59 long _rootObjectID = 0;
60 byte[] arrayBuffer;
61 int ArrayBufferLength = 4096;
63 class TypeMetadata
65 public Type Type;
66 public Type[] MemberTypes;
67 public string[] MemberNames;
68 public MemberInfo[] MemberInfos;
69 public int FieldCount;
70 public bool NeedsSerializationInfo;
73 class ArrayNullFiller
75 public ArrayNullFiller(int count) { NullCount = count; }
76 public int NullCount;
79 public ObjectReader (BinaryFormatter formatter)
81 // _formatter = formatter;
82 _surrogateSelector = formatter.SurrogateSelector;
83 _context = formatter.Context;
84 _binder = formatter.Binder;
85 _manager = new ObjectManager (_surrogateSelector, _context);
87 #if NET_1_1
88 _filterLevel = formatter.FilterLevel;
89 #endif
92 public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
94 BinaryElement elem = (BinaryElement)reader.ReadByte ();
95 ReadObjectGraph (elem, reader, readHeaders, out result, out headers);
98 public void ReadObjectGraph (BinaryElement elem, BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
100 headers = null;
102 // Reads the objects. The first object in the stream is the
103 // root object.
104 bool next = ReadNextObject (elem, reader);
105 if (next) {
106 do {
107 if (readHeaders && (headers == null))
108 headers = (Header[])CurrentObject;
109 else
110 if (_rootObjectID == 0) _rootObjectID = _lastObjectID;
111 } while (ReadNextObject (reader));
114 result = _manager.GetObject (_rootObjectID);
117 bool ReadNextObject (BinaryElement element, BinaryReader reader)
119 if (element == BinaryElement.End)
121 _manager.DoFixups();
123 _manager.RaiseDeserializationEvent();
124 return false;
127 SerializationInfo info;
128 long objectId;
130 ReadObject (element, reader, out objectId, out _lastObject, out info);
132 if (objectId != 0) {
133 RegisterObject (objectId, _lastObject, info, 0, null, null);
134 _lastObjectID = objectId;
137 return true;
140 public bool ReadNextObject (BinaryReader reader)
142 BinaryElement element = (BinaryElement)reader.ReadByte ();
143 if (element == BinaryElement.End)
145 _manager.DoFixups();
147 _manager.RaiseDeserializationEvent();
148 return false;
151 SerializationInfo info;
152 long objectId;
154 ReadObject (element, reader, out objectId, out _lastObject, out info);
156 if (objectId != 0) {
157 RegisterObject (objectId, _lastObject, info, 0, null, null);
158 _lastObjectID = objectId;
161 return true;
164 public object CurrentObject
166 get { return _lastObject; }
169 // Reads an object from the stream. The object is registered in the ObjectManager.
170 // The result can be either the object instance
171 // or the id of the object (when what is found in the stream is an object reference).
172 // If an object instance is read, the objectId is set to 0.
174 private void ReadObject (BinaryElement element, BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
176 switch (element)
178 case BinaryElement.RefTypeObject:
179 ReadRefTypeObjectInstance (reader, out objectId, out value, out info);
180 break;
182 case BinaryElement.UntypedRuntimeObject:
183 ReadObjectInstance (reader, true, false, out objectId, out value, out info);
184 break;
186 case BinaryElement.UntypedExternalObject:
187 ReadObjectInstance (reader, false, false, out objectId, out value, out info);
188 break;
190 case BinaryElement.RuntimeObject:
191 ReadObjectInstance (reader, true, true, out objectId, out value, out info);
192 break;
194 case BinaryElement.ExternalObject:
195 ReadObjectInstance (reader, false, true, out objectId, out value, out info);
196 break;
198 case BinaryElement.String:
199 info = null;
200 ReadStringIntance (reader, out objectId, out value);
201 break;
203 case BinaryElement.GenericArray:
204 info = null;
205 ReadGenericArray (reader, out objectId, out value);
206 break;
209 case BinaryElement.BoxedPrimitiveTypeValue:
210 value = ReadBoxedPrimitiveTypeValue (reader);
211 objectId = 0;
212 info = null;
213 break;
215 case BinaryElement.NullValue:
216 value = null;
217 objectId = 0;
218 info = null;
219 break;
221 case BinaryElement.Assembly:
222 ReadAssembly (reader);
223 ReadObject ((BinaryElement)reader.ReadByte (), reader, out objectId, out value, out info);
224 break;
226 case BinaryElement.ArrayFiller8b:
227 value = new ArrayNullFiller(reader.ReadByte());
228 objectId = 0;
229 info = null;
230 break;
232 case BinaryElement.ArrayFiller32b:
233 value = new ArrayNullFiller(reader.ReadInt32());
234 objectId = 0;
235 info = null;
236 break;
238 case BinaryElement.ArrayOfPrimitiveType:
239 ReadArrayOfPrimitiveType (reader, out objectId, out value);
240 info = null;
241 break;
243 case BinaryElement.ArrayOfObject:
244 ReadArrayOfObject (reader, out objectId, out value);
245 info = null;
246 break;
248 case BinaryElement.ArrayOfString:
249 ReadArrayOfString (reader, out objectId, out value);
250 info = null;
251 break;
253 default:
254 throw new SerializationException ("Unexpected binary element: " + (int)element);
258 private void ReadAssembly (BinaryReader reader)
260 long id = (long) reader.ReadUInt32 ();
261 string assemblyName = reader.ReadString ();
262 _registeredAssemblies [id] = assemblyName;
265 private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo, out long objectId, out object value, out SerializationInfo info)
267 objectId = (long) reader.ReadUInt32 ();
269 TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject, hasTypeInfo);
270 ReadObjectContent (reader, metadata, objectId, out value, out info);
273 private void ReadRefTypeObjectInstance (BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
275 objectId = (long) reader.ReadUInt32 ();
276 long refTypeObjectId = (long) reader.ReadUInt32 ();
278 // Gets the type of the referred object and its metadata
280 object refObj = _manager.GetObject (refTypeObjectId);
281 if (refObj == null) throw new SerializationException ("Invalid binary format");
282 TypeMetadata metadata = (TypeMetadata)_typeMetadataCache [refObj.GetType()];
284 ReadObjectContent (reader, metadata, objectId, out value, out info);
287 private void ReadObjectContent (BinaryReader reader, TypeMetadata metadata, long objectId, out object objectInstance, out SerializationInfo info)
289 if (_filterLevel == TypeFilterLevel.Low)
290 objectInstance = FormatterServices.GetSafeUninitializedObject (metadata.Type);
291 else
292 objectInstance = FormatterServices.GetUninitializedObject (metadata.Type);
293 _manager.RaiseOnDeserializingEvent (objectInstance);
295 info = metadata.NeedsSerializationInfo ? new SerializationInfo(metadata.Type, new FormatterConverter()) : null;
297 if (metadata.MemberNames != null)
298 for (int n=0; n<metadata.FieldCount; n++)
299 ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberNames[n], null, null);
300 else
301 for (int n=0; n<metadata.FieldCount; n++)
302 ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberInfos[n].Name, metadata.MemberInfos[n], null);
305 private void RegisterObject (long objectId, object objectInstance, SerializationInfo info, long parentObjectId, MemberInfo parentObjectMemeber, int[] indices)
307 if (parentObjectId == 0) indices = null;
309 if (!objectInstance.GetType().IsValueType || parentObjectId == 0)
310 _manager.RegisterObject (objectInstance, objectId, info, 0, null, null);
311 else
313 if (indices != null) indices = (int[])indices.Clone();
314 _manager.RegisterObject (objectInstance, objectId, info, parentObjectId, parentObjectMemeber, indices);
318 private void ReadStringIntance (BinaryReader reader, out long objectId, out object value)
320 objectId = (long) reader.ReadUInt32 ();
321 value = reader.ReadString ();
324 private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)
326 objectId = (long) reader.ReadUInt32 ();
327 // Array structure
328 reader.ReadByte();
330 int rank = reader.ReadInt32();
332 bool emptyDim = false;
333 int[] lengths = new int[rank];
334 for (int n=0; n<rank; n++)
336 lengths[n] = reader.ReadInt32();
337 if (lengths[n] == 0) emptyDim = true;
340 TypeTag code = (TypeTag) reader.ReadByte ();
341 Type elementType = ReadType (reader, code);
343 Array array = Array.CreateInstance (elementType, lengths);
345 if (emptyDim)
347 val = array;
348 return;
351 int[] indices = new int[rank];
353 // Initialize indexes
354 for (int dim = rank-1; dim >= 0; dim--)
355 indices[dim] = array.GetLowerBound (dim);
357 bool end = false;
358 while (!end)
360 ReadValue (reader, array, objectId, null, elementType, null, null, indices);
362 for (int dim = array.Rank-1; dim >= 0; dim--)
364 indices[dim]++;
365 if (indices[dim] > array.GetUpperBound (dim))
367 if (dim > 0)
369 indices[dim] = array.GetLowerBound (dim);
370 continue; // Increment the next dimension's index
372 end = true; // That was the last dimension. Finished.
374 break;
377 val = array;
380 private object ReadBoxedPrimitiveTypeValue (BinaryReader reader)
382 Type type = ReadType (reader, TypeTag.PrimitiveType);
383 return ReadPrimitiveTypeValue (reader, type);
386 private void ReadArrayOfPrimitiveType (BinaryReader reader, out long objectId, out object val)
388 objectId = (long) reader.ReadUInt32 ();
389 int length = reader.ReadInt32 ();
390 Type elementType = ReadType (reader, TypeTag.PrimitiveType);
392 switch (Type.GetTypeCode (elementType))
394 case TypeCode.Boolean: {
395 bool[] arr = new bool [length];
396 for (int n = 0; n < length; n++) arr [n] = reader.ReadBoolean();
397 val = arr;
398 break;
401 case TypeCode.Byte: {
402 byte[] arr = new byte [length];
403 int pos = 0;
404 while (pos < length) {
405 int nr = reader.Read (arr, pos, length - pos);
406 if (nr == 0) break;
407 pos += nr;
409 val = arr;
410 break;
413 case TypeCode.Char: {
414 char[] arr = new char [length];
415 int pos = 0;
416 while (pos < length) {
417 int nr = reader.Read (arr, pos, length - pos);
418 if (nr == 0) break;
419 pos += nr;
421 val = arr;
422 break;
425 case TypeCode.DateTime: {
426 DateTime[] arr = new DateTime [length];
427 for (int n = 0; n < length; n++) {
428 arr [n] = DateTime.FromBinary (reader.ReadInt64 ());
430 val = arr;
431 break;
434 case TypeCode.Decimal: {
435 Decimal[] arr = new Decimal [length];
436 for (int n = 0; n < length; n++) arr [n] = reader.ReadDecimal();
437 val = arr;
438 break;
441 case TypeCode.Double: {
442 Double[] arr = new Double [length];
443 if (length > 2)
444 BlockRead (reader, arr, 8);
445 else
446 for (int n = 0; n < length; n++) arr [n] = reader.ReadDouble();
447 val = arr;
448 break;
451 case TypeCode.Int16: {
452 short[] arr = new short [length];
453 if (length > 2)
454 BlockRead (reader, arr, 2);
455 else
456 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt16();
457 val = arr;
458 break;
461 case TypeCode.Int32: {
462 int[] arr = new int [length];
463 if (length > 2)
464 BlockRead (reader, arr, 4);
465 else
466 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt32();
467 val = arr;
468 break;
471 case TypeCode.Int64: {
472 long[] arr = new long [length];
473 if (length > 2)
474 BlockRead (reader, arr, 8);
475 else
476 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt64();
477 val = arr;
478 break;
481 case TypeCode.SByte: {
482 sbyte[] arr = new sbyte [length];
483 if (length > 2)
484 BlockRead (reader, arr, 1);
485 else
486 for (int n = 0; n < length; n++) arr [n] = reader.ReadSByte();
487 val = arr;
488 break;
491 case TypeCode.Single: {
492 float[] arr = new float [length];
493 if (length > 2)
494 BlockRead (reader, arr, 4);
495 else
496 for (int n = 0; n < length; n++) arr [n] = reader.ReadSingle();
497 val = arr;
498 break;
501 case TypeCode.UInt16: {
502 ushort[] arr = new ushort [length];
503 if (length > 2)
504 BlockRead (reader, arr, 2);
505 else
506 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt16();
507 val = arr;
508 break;
511 case TypeCode.UInt32: {
512 uint[] arr = new uint [length];
513 if (length > 2)
514 BlockRead (reader, arr, 4);
515 else
516 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt32();
517 val = arr;
518 break;
521 case TypeCode.UInt64: {
522 ulong[] arr = new ulong [length];
523 if (length > 2)
524 BlockRead (reader, arr, 8);
525 else
526 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt64();
527 val = arr;
528 break;
531 case TypeCode.String: {
532 string[] arr = new string [length];
533 for (int n = 0; n < length; n++) arr [n] = reader.ReadString();
534 val = arr;
535 break;
538 default: {
539 if (elementType == typeof(TimeSpan)) {
540 TimeSpan[] arr = new TimeSpan [length];
541 for (int n = 0; n < length; n++) arr [n] = new TimeSpan (reader.ReadInt64 ());
542 val = arr;
544 else
545 throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
546 break;
551 private void BlockRead (BinaryReader reader, Array array, int dataSize)
553 int totalSize = Buffer.ByteLength (array);
555 if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
556 arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
558 int pos = 0;
559 while (totalSize > 0) {
560 int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
561 int ap = 0;
562 do {
563 int nr = reader.Read (arrayBuffer, ap, size - ap);
564 if (nr == 0) break;
565 ap += nr;
566 } while (ap < size);
568 if (!BitConverter.IsLittleEndian && dataSize > 1)
569 BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
571 Buffer.BlockCopy (arrayBuffer, 0, array, pos, size);
572 totalSize -= size;
573 pos += size;
578 private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)
580 ReadSimpleArray (reader, typeof (object), out objectId, out array);
583 private void ReadArrayOfString (BinaryReader reader, out long objectId, out object array)
585 ReadSimpleArray (reader, typeof (string), out objectId, out array);
588 private void ReadSimpleArray (BinaryReader reader, Type elementType, out long objectId, out object val)
590 objectId = (long) reader.ReadUInt32 ();
591 int length = reader.ReadInt32 ();
592 int[] indices = new int[1];
594 Array array = Array.CreateInstance (elementType, length);
595 for (int n = 0; n < length; n++)
597 indices[0] = n;
598 ReadValue (reader, array, objectId, null, elementType, null, null, indices);
599 n = indices[0];
601 val = array;
604 private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo)
606 TypeMetadata metadata = new TypeMetadata();
608 string className = reader.ReadString ();
609 int fieldCount = reader.ReadInt32 ();
611 Type[] types = new Type[fieldCount];
612 string[] names = new string[fieldCount];
614 for (int n=0; n<fieldCount; n++)
615 names [n] = reader.ReadString ();
617 if (hasTypeInfo)
619 TypeTag[] codes = new TypeTag[fieldCount];
621 for (int n=0; n<fieldCount; n++)
622 codes [n] = (TypeTag) reader.ReadByte ();
624 for (int n=0; n<fieldCount; n++) {
625 Type t = ReadType (reader, codes[n], false);
626 // The field's type could not be resolved: assume it is an object.
627 if (t == null)
628 t = typeof (object);
629 types [n] = t;
633 // Gets the type
635 if (!isRuntimeObject)
637 long assemblyId = (long)reader.ReadUInt32();
638 metadata.Type = GetDeserializationType (assemblyId, className);
640 else
641 metadata.Type = Type.GetType (className, true);
643 metadata.MemberTypes = types;
644 metadata.MemberNames = names;
645 metadata.FieldCount = names.Length;
647 // Now check if this objects needs a SerializationInfo struct for deserialziation.
648 // SerializationInfo is needed if the object has to be deserialized using
649 // a serialization surrogate, or if it implements ISerializable.
651 if (_surrogateSelector != null)
653 // check if the surrogate selector handles objects of the given type.
654 ISurrogateSelector selector;
655 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.Type, _context, out selector);
656 metadata.NeedsSerializationInfo = (surrogate != null);
659 if (!metadata.NeedsSerializationInfo)
661 // Check if the object is marked with the Serializable attribute
663 if (!metadata.Type.IsSerializable)
664 throw new SerializationException("Serializable objects must be marked with the Serializable attribute");
666 metadata.NeedsSerializationInfo = typeof (ISerializable).IsAssignableFrom (metadata.Type);
667 if (!metadata.NeedsSerializationInfo)
669 metadata.MemberInfos = new MemberInfo [fieldCount];
670 for (int n=0; n<fieldCount; n++)
672 FieldInfo field = null;
673 string memberName = names[n];
675 int i = memberName.IndexOf ('+');
676 if (i != -1) {
677 string baseTypeName = names[n].Substring (0,i);
678 memberName = names[n].Substring (i+1);
679 Type t = metadata.Type.BaseType;
680 while (t != null) {
681 if (t.Name == baseTypeName) {
682 field = t.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
683 break;
685 else
686 t = t.BaseType;
689 else
690 field = metadata.Type.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
692 if (field == null) throw new SerializationException ("Field \"" + names[n] + "\" not found in class " + metadata.Type.FullName);
693 metadata.MemberInfos [n] = field;
695 if (!hasTypeInfo) {
696 types [n] = field.FieldType;
699 metadata.MemberNames = null; // Info now in MemberInfos
703 // Registers the type's metadata so it can be reused later if
704 // a RefTypeObject element is found
706 if (!_typeMetadataCache.ContainsKey (metadata.Type))
707 _typeMetadataCache [metadata.Type] = metadata;
709 return metadata;
713 private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, MemberInfo memberInfo, int[] indices)
715 // Reads a value from the stream and assigns it to the member of an object
717 object val;
719 if (BinaryCommon.IsPrimitive (valueType))
721 val = ReadPrimitiveTypeValue (reader, valueType);
722 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
723 return;
726 // Gets the object
728 BinaryElement element = (BinaryElement)reader.ReadByte ();
730 if (element == BinaryElement.ObjectReference)
732 // Just read the id of the referred object and record a fixup
733 long childObjectId = (long) reader.ReadUInt32();
734 RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);
735 return;
738 long objectId;
739 SerializationInfo objectInfo;
741 ReadObject (element, reader, out objectId, out val, out objectInfo);
743 // There are two cases where the object cannot be assigned to the parent
744 // and a fixup must be used:
745 // 1) When what has been read is not an object, but an id of an object that
746 // has not been read yet (an object reference). This is managed in the
747 // previous block of code.
748 // 2) When the read object is a value type object. Value type fields hold
749 // copies of objects, not references. Thus, if the value object that
750 // has been read has pending fixups, those fixups would be made to the
751 // boxed copy in the ObjectManager, and not in the required object instance
753 // First of all register the fixup, and then the object. ObjectManager is more
754 // efficient if done in this order
756 bool hasFixup = false;
757 if (objectId != 0)
759 if (val.GetType().IsValueType)
761 RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);
762 hasFixup = true;
765 // Register the value
767 if (info == null && !(parentObject is Array))
768 RegisterObject (objectId, val, objectInfo, parentObjectId, memberInfo, null);
769 else
770 RegisterObject (objectId, val, objectInfo, parentObjectId, null, indices);
772 // Assign the value to the parent object, unless there is a fixup
774 if (!hasFixup)
775 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
778 private void SetObjectValue (object parentObject, string fieldName, MemberInfo memberInfo, SerializationInfo info, object value, Type valueType, int[] indices)
780 if (value is IObjectReference)
781 value = ((IObjectReference)value).GetRealObject (_context);
783 if (parentObject is Array)
785 if (value is ArrayNullFiller)
787 // It must be a single dimension array of objects.
788 // Just increase the index. Elements are null by default.
789 int count = ((ArrayNullFiller)value).NullCount;
790 indices[0] += count - 1;
792 else
793 ((Array)parentObject).SetValue (value, indices);
795 else if (info != null) {
796 info.AddValue (fieldName, value, valueType);
798 else {
799 if (memberInfo is FieldInfo)
800 ((FieldInfo)memberInfo).SetValue (parentObject, value);
801 else
802 ((PropertyInfo)memberInfo).SetValue (parentObject, value, null);
806 private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, MemberInfo memberInfo, int[] indices)
808 if (info != null) {
809 _manager.RecordDelayedFixup (parentObjectId, fieldName, childObjectId);
811 else if (parentObject is Array) {
812 if (indices.Length == 1)
813 _manager.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);
814 else
815 _manager.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);
817 else {
818 _manager.RecordFixup (parentObjectId, memberInfo, childObjectId);
822 private Type GetDeserializationType (long assemblyId, string className)
824 return GetDeserializationType (assemblyId, className, true);
827 private Type GetDeserializationType (long assemblyId, string className, bool throwOnError)
829 Type t;
830 string assemblyName = (string)_registeredAssemblies[assemblyId];
832 if (_binder != null) {
833 t = _binder.BindToType (assemblyName, className);
834 if (t != null)
835 return t;
838 Assembly assembly;
839 try {
840 assembly = Assembly.Load (assemblyName);
841 } catch (Exception ex) {
842 if (!throwOnError)
843 return null;
844 throw new SerializationException (String.Format ("Couldn't find assembly '{0}'", assemblyName), ex);
847 t = assembly.GetType (className);
848 if (t != null)
849 return t;
851 if (!throwOnError)
852 return null;
854 throw new SerializationException (String.Format ("Couldn't find type '{0}' in assembly '{1}'", className, assemblyName));
857 public Type ReadType (BinaryReader reader, TypeTag code)
859 return ReadType (reader, code, true);
862 public Type ReadType (BinaryReader reader, TypeTag code, bool throwOnError)
864 switch (code)
866 case TypeTag.PrimitiveType:
867 return BinaryCommon.GetTypeFromCode (reader.ReadByte());
869 case TypeTag.String:
870 return typeof(string);
872 case TypeTag.ObjectType:
873 return typeof(object);
875 case TypeTag.RuntimeType:
877 string name = reader.ReadString ();
878 // map MS.NET's System.RuntimeType to System.MonoType
879 if (_context.State == StreamingContextStates.Remoting)
880 if (name == "System.RuntimeType")
881 return typeof (MonoType);
882 else if (name == "System.RuntimeType[]")
883 return typeof (MonoType[]);
884 Type t = Type.GetType (name);
885 if (t != null)
886 return t;
888 throw new SerializationException (String.Format ("Could not find type '{0}'.", name));
891 case TypeTag.GenericType:
893 string name = reader.ReadString ();
894 long asmid = (long) reader.ReadUInt32();
895 return GetDeserializationType (asmid, name, throwOnError);
898 case TypeTag.ArrayOfObject:
899 return typeof(object[]);
901 case TypeTag.ArrayOfString:
902 return typeof(string[]);
904 case TypeTag.ArrayOfPrimitiveType:
905 Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());
906 return Type.GetType(elementType.FullName + "[]");
908 default:
909 throw new NotSupportedException ("Unknow type tag");
913 public static object ReadPrimitiveTypeValue (BinaryReader reader, Type type)
915 if (type == null) return null;
917 switch (Type.GetTypeCode (type))
919 case TypeCode.Boolean:
920 return reader.ReadBoolean();
922 case TypeCode.Byte:
923 return reader.ReadByte();
925 case TypeCode.Char:
926 return reader.ReadChar();
928 case TypeCode.DateTime:
929 return DateTime.FromBinary (reader.ReadInt64());
931 case TypeCode.Decimal:
932 return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);
934 case TypeCode.Double:
935 return reader.ReadDouble();
937 case TypeCode.Int16:
938 return reader.ReadInt16();
940 case TypeCode.Int32:
941 return reader.ReadInt32();
943 case TypeCode.Int64:
944 return reader.ReadInt64();
946 case TypeCode.SByte:
947 return reader.ReadSByte();
949 case TypeCode.Single:
950 return reader.ReadSingle();
952 case TypeCode.UInt16:
953 return reader.ReadUInt16();
955 case TypeCode.UInt32:
956 return reader.ReadUInt32();
958 case TypeCode.UInt64:
959 return reader.ReadUInt64();
961 case TypeCode.String:
962 return reader.ReadString();
964 default:
965 if (type == typeof(TimeSpan))
966 return new TimeSpan (reader.ReadInt64 ());
967 else
968 throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);