4 // Lluis Sanchez Gual (lluis@ideary.com)
7 // (C) 2003 Lluis Sanchez Gual
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
33 using System.Runtime.Serialization;
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;
50 TypeFilterLevel _filterLevel;
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;
61 int ArrayBufferLength = 4096;
66 public Type[] MemberTypes;
67 public string[] MemberNames;
68 public MemberInfo[] MemberInfos;
69 public int FieldCount;
70 public bool NeedsSerializationInfo;
75 public ArrayNullFiller(int count) { NullCount = count; }
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);
88 _filterLevel = formatter.FilterLevel;
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)
102 // Reads the objects. The first object in the stream is the
104 bool next = ReadNextObject (elem, reader);
107 if (readHeaders && (headers == null))
108 headers = (Header[])CurrentObject;
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)
123 _manager.RaiseDeserializationEvent();
127 SerializationInfo info;
130 ReadObject (element, reader, out objectId, out _lastObject, out info);
133 RegisterObject (objectId, _lastObject, info, 0, null, null);
134 _lastObjectID = objectId;
140 public bool ReadNextObject (BinaryReader reader)
142 BinaryElement element = (BinaryElement)reader.ReadByte ();
143 if (element == BinaryElement.End)
147 _manager.RaiseDeserializationEvent();
151 SerializationInfo info;
154 ReadObject (element, reader, out objectId, out _lastObject, out info);
157 RegisterObject (objectId, _lastObject, info, 0, null, null);
158 _lastObjectID = objectId;
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)
178 case BinaryElement.RefTypeObject:
179 ReadRefTypeObjectInstance (reader, out objectId, out value, out info);
182 case BinaryElement.UntypedRuntimeObject:
183 ReadObjectInstance (reader, true, false, out objectId, out value, out info);
186 case BinaryElement.UntypedExternalObject:
187 ReadObjectInstance (reader, false, false, out objectId, out value, out info);
190 case BinaryElement.RuntimeObject:
191 ReadObjectInstance (reader, true, true, out objectId, out value, out info);
194 case BinaryElement.ExternalObject:
195 ReadObjectInstance (reader, false, true, out objectId, out value, out info);
198 case BinaryElement.String:
200 ReadStringIntance (reader, out objectId, out value);
203 case BinaryElement.GenericArray:
205 ReadGenericArray (reader, out objectId, out value);
209 case BinaryElement.BoxedPrimitiveTypeValue:
210 value = ReadBoxedPrimitiveTypeValue (reader);
215 case BinaryElement.NullValue:
221 case BinaryElement.Assembly:
222 ReadAssembly (reader);
223 ReadObject ((BinaryElement)reader.ReadByte (), reader, out objectId, out value, out info);
226 case BinaryElement.ArrayFiller8b:
227 value = new ArrayNullFiller(reader.ReadByte());
232 case BinaryElement.ArrayFiller32b:
233 value = new ArrayNullFiller(reader.ReadInt32());
238 case BinaryElement.ArrayOfPrimitiveType:
239 ReadArrayOfPrimitiveType (reader, out objectId, out value);
243 case BinaryElement.ArrayOfObject:
244 ReadArrayOfObject (reader, out objectId, out value);
248 case BinaryElement.ArrayOfString:
249 ReadArrayOfString (reader, out objectId, out value);
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);
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);
301 for (int n=0; n<metadata.FieldCount; n++) {
302 if (metadata.MemberInfos [n] != null)
303 ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberInfos[n].Name, metadata.MemberInfos[n], null);
304 else if (BinaryCommon.IsPrimitive(metadata.MemberTypes[n])) {
305 // Since the member info is null, the type in this
306 // domain does not have this type. Even though we
307 // are not going to store the value, we will read
308 // it from the stream so that we can advance to the
310 ReadPrimitiveTypeValue (reader, metadata.MemberTypes[n]);
315 private void RegisterObject (long objectId, object objectInstance, SerializationInfo info, long parentObjectId, MemberInfo parentObjectMemeber, int[] indices)
317 if (parentObjectId == 0) indices = null;
319 if (!objectInstance.GetType().IsValueType || parentObjectId == 0)
320 _manager.RegisterObject (objectInstance, objectId, info, 0, null, null);
323 if (indices != null) indices = (int[])indices.Clone();
324 _manager.RegisterObject (objectInstance, objectId, info, parentObjectId, parentObjectMemeber, indices);
328 private void ReadStringIntance (BinaryReader reader, out long objectId, out object value)
330 objectId = (long) reader.ReadUInt32 ();
331 value = reader.ReadString ();
334 private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)
336 objectId = (long) reader.ReadUInt32 ();
340 int rank = reader.ReadInt32();
342 bool emptyDim = false;
343 int[] lengths = new int[rank];
344 for (int n=0; n<rank; n++)
346 lengths[n] = reader.ReadInt32();
347 if (lengths[n] == 0) emptyDim = true;
350 TypeTag code = (TypeTag) reader.ReadByte ();
351 Type elementType = ReadType (reader, code);
353 Array array = Array.CreateInstance (elementType, lengths);
361 int[] indices = new int[rank];
363 // Initialize indexes
364 for (int dim = rank-1; dim >= 0; dim--)
365 indices[dim] = array.GetLowerBound (dim);
370 ReadValue (reader, array, objectId, null, elementType, null, null, indices);
372 for (int dim = array.Rank-1; dim >= 0; dim--)
375 if (indices[dim] > array.GetUpperBound (dim))
379 indices[dim] = array.GetLowerBound (dim);
380 continue; // Increment the next dimension's index
382 end = true; // That was the last dimension. Finished.
390 private object ReadBoxedPrimitiveTypeValue (BinaryReader reader)
392 Type type = ReadType (reader, TypeTag.PrimitiveType);
393 return ReadPrimitiveTypeValue (reader, type);
396 private void ReadArrayOfPrimitiveType (BinaryReader reader, out long objectId, out object val)
398 objectId = (long) reader.ReadUInt32 ();
399 int length = reader.ReadInt32 ();
400 Type elementType = ReadType (reader, TypeTag.PrimitiveType);
402 switch (Type.GetTypeCode (elementType))
404 case TypeCode.Boolean: {
405 bool[] arr = new bool [length];
406 for (int n = 0; n < length; n++) arr [n] = reader.ReadBoolean();
411 case TypeCode.Byte: {
412 byte[] arr = new byte [length];
414 while (pos < length) {
415 int nr = reader.Read (arr, pos, length - pos);
423 case TypeCode.Char: {
424 char[] arr = new char [length];
426 while (pos < length) {
427 int nr = reader.Read (arr, pos, length - pos);
435 case TypeCode.DateTime: {
436 DateTime[] arr = new DateTime [length];
437 for (int n = 0; n < length; n++) {
438 arr [n] = DateTime.FromBinary (reader.ReadInt64 ());
444 case TypeCode.Decimal: {
445 Decimal[] arr = new Decimal [length];
446 for (int n = 0; n < length; n++) arr [n] = reader.ReadDecimal();
451 case TypeCode.Double: {
452 Double[] arr = new Double [length];
454 BlockRead (reader, arr, 8);
456 for (int n = 0; n < length; n++) arr [n] = reader.ReadDouble();
461 case TypeCode.Int16: {
462 short[] arr = new short [length];
464 BlockRead (reader, arr, 2);
466 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt16();
471 case TypeCode.Int32: {
472 int[] arr = new int [length];
474 BlockRead (reader, arr, 4);
476 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt32();
481 case TypeCode.Int64: {
482 long[] arr = new long [length];
484 BlockRead (reader, arr, 8);
486 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt64();
491 case TypeCode.SByte: {
492 sbyte[] arr = new sbyte [length];
494 BlockRead (reader, arr, 1);
496 for (int n = 0; n < length; n++) arr [n] = reader.ReadSByte();
501 case TypeCode.Single: {
502 float[] arr = new float [length];
504 BlockRead (reader, arr, 4);
506 for (int n = 0; n < length; n++) arr [n] = reader.ReadSingle();
511 case TypeCode.UInt16: {
512 ushort[] arr = new ushort [length];
514 BlockRead (reader, arr, 2);
516 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt16();
521 case TypeCode.UInt32: {
522 uint[] arr = new uint [length];
524 BlockRead (reader, arr, 4);
526 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt32();
531 case TypeCode.UInt64: {
532 ulong[] arr = new ulong [length];
534 BlockRead (reader, arr, 8);
536 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt64();
541 case TypeCode.String: {
542 string[] arr = new string [length];
543 for (int n = 0; n < length; n++) arr [n] = reader.ReadString();
549 if (elementType == typeof(TimeSpan)) {
550 TimeSpan[] arr = new TimeSpan [length];
551 for (int n = 0; n < length; n++) arr [n] = new TimeSpan (reader.ReadInt64 ());
555 throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
561 private void BlockRead (BinaryReader reader, Array array, int dataSize)
563 int totalSize = Buffer.ByteLength (array);
565 if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
566 arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
569 while (totalSize > 0) {
570 int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
573 int nr = reader.Read (arrayBuffer, ap, size - ap);
578 if (!BitConverter.IsLittleEndian && dataSize > 1)
579 BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
581 Buffer.BlockCopy (arrayBuffer, 0, array, pos, size);
588 private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)
590 ReadSimpleArray (reader, typeof (object), out objectId, out array);
593 private void ReadArrayOfString (BinaryReader reader, out long objectId, out object array)
595 ReadSimpleArray (reader, typeof (string), out objectId, out array);
598 private void ReadSimpleArray (BinaryReader reader, Type elementType, out long objectId, out object val)
600 objectId = (long) reader.ReadUInt32 ();
601 int length = reader.ReadInt32 ();
602 int[] indices = new int[1];
604 Array array = Array.CreateInstance (elementType, length);
605 for (int n = 0; n < length; n++)
608 ReadValue (reader, array, objectId, null, elementType, null, null, indices);
614 private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo)
616 TypeMetadata metadata = new TypeMetadata();
618 string className = reader.ReadString ();
619 int fieldCount = reader.ReadInt32 ();
621 Type[] types = new Type[fieldCount];
622 string[] names = new string[fieldCount];
624 for (int n=0; n<fieldCount; n++)
625 names [n] = reader.ReadString ();
629 TypeTag[] codes = new TypeTag[fieldCount];
631 for (int n=0; n<fieldCount; n++)
632 codes [n] = (TypeTag) reader.ReadByte ();
634 for (int n=0; n<fieldCount; n++) {
635 Type t = ReadType (reader, codes[n], false);
636 // The field's type could not be resolved: assume it is an object.
645 if (!isRuntimeObject)
647 long assemblyId = (long)reader.ReadUInt32();
648 metadata.Type = GetDeserializationType (assemblyId, className);
651 metadata.Type = Type.GetType (className, true);
653 metadata.MemberTypes = types;
654 metadata.MemberNames = names;
655 metadata.FieldCount = names.Length;
657 // Now check if this objects needs a SerializationInfo struct for deserialziation.
658 // SerializationInfo is needed if the object has to be deserialized using
659 // a serialization surrogate, or if it implements ISerializable.
661 if (_surrogateSelector != null)
663 // check if the surrogate selector handles objects of the given type.
664 ISurrogateSelector selector;
665 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.Type, _context, out selector);
666 metadata.NeedsSerializationInfo = (surrogate != null);
669 if (!metadata.NeedsSerializationInfo)
671 // Check if the object is marked with the Serializable attribute
673 if (!metadata.Type.IsSerializable)
674 throw new SerializationException("Serializable objects must be marked with the Serializable attribute");
676 metadata.NeedsSerializationInfo = typeof (ISerializable).IsAssignableFrom (metadata.Type);
677 if (!metadata.NeedsSerializationInfo)
679 metadata.MemberInfos = new MemberInfo [fieldCount];
680 for (int n=0; n<fieldCount; n++)
682 FieldInfo field = null;
683 string memberName = names[n];
685 int i = memberName.IndexOf ('+');
687 string baseTypeName = names[n].Substring (0,i);
688 memberName = names[n].Substring (i+1);
689 Type t = metadata.Type.BaseType;
691 if (t.Name == baseTypeName) {
692 field = t.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
700 field = metadata.Type.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
703 metadata.MemberInfos [n] = field;
706 throw new SerializationException ("Field \"" + names[n] + "\" not found in class " + metadata.Type.FullName);
710 types [n] = field.FieldType;
713 metadata.MemberNames = null; // Info now in MemberInfos
717 // Registers the type's metadata so it can be reused later if
718 // a RefTypeObject element is found
720 if (!_typeMetadataCache.ContainsKey (metadata.Type))
721 _typeMetadataCache [metadata.Type] = metadata;
726 // Called for primitive types
727 static bool IsGeneric (MemberInfo minfo)
733 switch (minfo.MemberType) {
734 case MemberTypes.Field:
735 mtype = ((FieldInfo) minfo).FieldType;
738 throw new NotSupportedException ("Not supported: " + minfo.MemberType);
740 return (mtype != null && mtype.IsGenericType);
743 private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, MemberInfo memberInfo, int[] indices)
745 // Reads a value from the stream and assigns it to the member of an object
749 if (BinaryCommon.IsPrimitive (valueType) && !IsGeneric (memberInfo))
751 val = ReadPrimitiveTypeValue (reader, valueType);
752 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
758 BinaryElement element = (BinaryElement)reader.ReadByte ();
760 if (element == BinaryElement.ObjectReference)
762 // Just read the id of the referred object and record a fixup
763 long childObjectId = (long) reader.ReadUInt32();
764 RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);
769 SerializationInfo objectInfo;
771 ReadObject (element, reader, out objectId, out val, out objectInfo);
773 // There are two cases where the object cannot be assigned to the parent
774 // and a fixup must be used:
775 // 1) When what has been read is not an object, but an id of an object that
776 // has not been read yet (an object reference). This is managed in the
777 // previous block of code.
778 // 2) When the read object is a value type object. Value type fields hold
779 // copies of objects, not references. Thus, if the value object that
780 // has been read has pending fixups, those fixups would be made to the
781 // boxed copy in the ObjectManager, and not in the required object instance
783 // First of all register the fixup, and then the object. ObjectManager is more
784 // efficient if done in this order
786 bool hasFixup = false;
789 if (val.GetType().IsValueType)
791 RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);
795 // Register the value
797 if (info == null && !(parentObject is Array))
798 RegisterObject (objectId, val, objectInfo, parentObjectId, memberInfo, null);
800 RegisterObject (objectId, val, objectInfo, parentObjectId, null, indices);
802 // Assign the value to the parent object, unless there is a fixup
805 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
808 private void SetObjectValue (object parentObject, string fieldName, MemberInfo memberInfo, SerializationInfo info, object value, Type valueType, int[] indices)
810 if (value is IObjectReference)
811 value = ((IObjectReference)value).GetRealObject (_context);
813 if (parentObject is Array)
815 if (value is ArrayNullFiller)
817 // It must be a single dimension array of objects.
818 // Just increase the index. Elements are null by default.
819 int count = ((ArrayNullFiller)value).NullCount;
820 indices[0] += count - 1;
823 ((Array)parentObject).SetValue (value, indices);
825 else if (info != null) {
826 info.AddValue (fieldName, value, valueType);
829 if (memberInfo is FieldInfo)
830 ((FieldInfo)memberInfo).SetValue (parentObject, value);
832 ((PropertyInfo)memberInfo).SetValue (parentObject, value, null);
836 private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, MemberInfo memberInfo, int[] indices)
839 _manager.RecordDelayedFixup (parentObjectId, fieldName, childObjectId);
841 else if (parentObject is Array) {
842 if (indices.Length == 1)
843 _manager.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);
845 _manager.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);
848 _manager.RecordFixup (parentObjectId, memberInfo, childObjectId);
852 private Type GetDeserializationType (long assemblyId, string className)
854 return GetDeserializationType (assemblyId, className, true);
857 private Type GetDeserializationType (long assemblyId, string className, bool throwOnError)
860 string assemblyName = (string)_registeredAssemblies[assemblyId];
862 if (_binder != null) {
863 t = _binder.BindToType (assemblyName, className);
870 assembly = Assembly.Load (assemblyName);
871 } catch (Exception ex) {
874 throw new SerializationException (String.Format ("Couldn't find assembly '{0}'", assemblyName), ex);
877 t = assembly.GetType (className);
884 throw new SerializationException (String.Format ("Couldn't find type '{0}' in assembly '{1}'", className, assemblyName));
887 public Type ReadType (BinaryReader reader, TypeTag code)
889 return ReadType (reader, code, true);
892 public Type ReadType (BinaryReader reader, TypeTag code, bool throwOnError)
896 case TypeTag.PrimitiveType:
897 return BinaryCommon.GetTypeFromCode (reader.ReadByte());
900 return typeof(string);
902 case TypeTag.ObjectType:
903 return typeof(object);
905 case TypeTag.RuntimeType:
907 string name = reader.ReadString ();
908 // map MS.NET's System.RuntimeType to System.MonoType
909 if (_context.State == StreamingContextStates.Remoting)
910 if (name == "System.RuntimeType")
911 return typeof (MonoType);
912 else if (name == "System.RuntimeType[]")
913 return typeof (MonoType[]);
914 Type t = Type.GetType (name);
918 throw new SerializationException (String.Format ("Could not find type '{0}'.", name));
921 case TypeTag.GenericType:
923 string name = reader.ReadString ();
924 long asmid = (long) reader.ReadUInt32();
925 return GetDeserializationType (asmid, name, throwOnError);
928 case TypeTag.ArrayOfObject:
929 return typeof(object[]);
931 case TypeTag.ArrayOfString:
932 return typeof(string[]);
934 case TypeTag.ArrayOfPrimitiveType:
935 Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());
936 return Type.GetType(elementType.FullName + "[]");
939 throw new NotSupportedException ("Unknow type tag");
943 public static object ReadPrimitiveTypeValue (BinaryReader reader, Type type)
945 if (type == null) return null;
947 switch (Type.GetTypeCode (type))
949 case TypeCode.Boolean:
950 return reader.ReadBoolean();
953 return reader.ReadByte();
956 return reader.ReadChar();
958 case TypeCode.DateTime:
959 return DateTime.FromBinary (reader.ReadInt64());
961 case TypeCode.Decimal:
962 return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);
964 case TypeCode.Double:
965 return reader.ReadDouble();
968 return reader.ReadInt16();
971 return reader.ReadInt32();
974 return reader.ReadInt64();
977 return reader.ReadSByte();
979 case TypeCode.Single:
980 return reader.ReadSingle();
982 case TypeCode.UInt16:
983 return reader.ReadUInt16();
985 case TypeCode.UInt32:
986 return reader.ReadUInt32();
988 case TypeCode.UInt64:
989 return reader.ReadUInt64();
991 case TypeCode.String:
992 return reader.ReadString();
995 if (type == typeof(TimeSpan))
996 return new TimeSpan (reader.ReadInt64 ());
998 throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);