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;
49 TypeFilterLevel _filterLevel;
51 ObjectManager _manager;
52 Hashtable _registeredAssemblies = new Hashtable();
53 Hashtable _typeMetadataCache = new Hashtable();
55 object _lastObject = null;
56 long _lastObjectID = 0;
57 long _rootObjectID = 0;
59 int ArrayBufferLength = 4096;
64 public Type[] MemberTypes;
65 public string[] MemberNames;
66 public MemberInfo[] MemberInfos;
67 public int FieldCount;
68 public bool NeedsSerializationInfo;
73 public ArrayNullFiller(int count) { NullCount = count; }
77 public ObjectReader (BinaryFormatter formatter)
79 // _formatter = formatter;
80 _surrogateSelector = formatter.SurrogateSelector;
81 _context = formatter.Context;
82 _binder = formatter.Binder;
83 _manager = new ObjectManager (_surrogateSelector, _context);
85 _filterLevel = formatter.FilterLevel;
88 public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
90 BinaryElement elem = (BinaryElement)reader.ReadByte ();
91 ReadObjectGraph (elem, reader, readHeaders, out result, out headers);
94 public void ReadObjectGraph (BinaryElement elem, BinaryReader reader, bool readHeaders, out object result, out Header[] headers)
98 // Reads the objects. The first object in the stream is the
100 bool next = ReadNextObject (elem, reader);
103 if (readHeaders && (headers == null))
104 headers = (Header[])CurrentObject;
106 if (_rootObjectID == 0) _rootObjectID = _lastObjectID;
107 } while (ReadNextObject (reader));
110 result = _manager.GetObject (_rootObjectID);
113 bool ReadNextObject (BinaryElement element, BinaryReader reader)
115 if (element == BinaryElement.End)
119 _manager.RaiseDeserializationEvent();
123 SerializationInfo info;
126 ReadObject (element, reader, out objectId, out _lastObject, out info);
129 RegisterObject (objectId, _lastObject, info, 0, null, null);
130 _lastObjectID = objectId;
136 public bool ReadNextObject (BinaryReader reader)
138 BinaryElement element = (BinaryElement)reader.ReadByte ();
139 if (element == BinaryElement.End)
143 _manager.RaiseDeserializationEvent();
147 SerializationInfo info;
150 ReadObject (element, reader, out objectId, out _lastObject, out info);
153 RegisterObject (objectId, _lastObject, info, 0, null, null);
154 _lastObjectID = objectId;
160 public object CurrentObject
162 get { return _lastObject; }
165 // Reads an object from the stream. The object is registered in the ObjectManager.
166 // The result can be either the object instance
167 // or the id of the object (when what is found in the stream is an object reference).
168 // If an object instance is read, the objectId is set to 0.
170 private void ReadObject (BinaryElement element, BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
174 case BinaryElement.RefTypeObject:
175 ReadRefTypeObjectInstance (reader, out objectId, out value, out info);
178 case BinaryElement.UntypedRuntimeObject:
179 ReadObjectInstance (reader, true, false, out objectId, out value, out info);
182 case BinaryElement.UntypedExternalObject:
183 ReadObjectInstance (reader, false, false, out objectId, out value, out info);
186 case BinaryElement.RuntimeObject:
187 ReadObjectInstance (reader, true, true, out objectId, out value, out info);
190 case BinaryElement.ExternalObject:
191 ReadObjectInstance (reader, false, true, out objectId, out value, out info);
194 case BinaryElement.String:
196 ReadStringIntance (reader, out objectId, out value);
199 case BinaryElement.GenericArray:
201 ReadGenericArray (reader, out objectId, out value);
205 case BinaryElement.BoxedPrimitiveTypeValue:
206 value = ReadBoxedPrimitiveTypeValue (reader);
211 case BinaryElement.NullValue:
217 case BinaryElement.Assembly:
218 ReadAssembly (reader);
219 ReadObject ((BinaryElement)reader.ReadByte (), reader, out objectId, out value, out info);
222 case BinaryElement.ArrayFiller8b:
223 value = new ArrayNullFiller(reader.ReadByte());
228 case BinaryElement.ArrayFiller32b:
229 value = new ArrayNullFiller(reader.ReadInt32());
234 case BinaryElement.ArrayOfPrimitiveType:
235 ReadArrayOfPrimitiveType (reader, out objectId, out value);
239 case BinaryElement.ArrayOfObject:
240 ReadArrayOfObject (reader, out objectId, out value);
244 case BinaryElement.ArrayOfString:
245 ReadArrayOfString (reader, out objectId, out value);
250 throw new SerializationException ("Unexpected binary element: " + (int)element);
254 private void ReadAssembly (BinaryReader reader)
256 long id = (long) reader.ReadUInt32 ();
257 string assemblyName = reader.ReadString ();
258 _registeredAssemblies [id] = assemblyName;
261 private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo, out long objectId, out object value, out SerializationInfo info)
263 objectId = (long) reader.ReadUInt32 ();
265 TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject, hasTypeInfo);
266 ReadObjectContent (reader, metadata, objectId, out value, out info);
269 private void ReadRefTypeObjectInstance (BinaryReader reader, out long objectId, out object value, out SerializationInfo info)
271 objectId = (long) reader.ReadUInt32 ();
272 long refTypeObjectId = (long) reader.ReadUInt32 ();
274 // Gets the type of the referred object and its metadata
276 object refObj = _manager.GetObject (refTypeObjectId);
277 if (refObj == null) throw new SerializationException ("Invalid binary format");
278 TypeMetadata metadata = (TypeMetadata)_typeMetadataCache [refObj.GetType()];
280 ReadObjectContent (reader, metadata, objectId, out value, out info);
283 private void ReadObjectContent (BinaryReader reader, TypeMetadata metadata, long objectId, out object objectInstance, out SerializationInfo info)
285 if (_filterLevel == TypeFilterLevel.Low)
286 objectInstance = FormatterServices.GetSafeUninitializedObject (metadata.Type);
288 objectInstance = FormatterServices.GetUninitializedObject (metadata.Type);
289 _manager.RaiseOnDeserializingEvent (objectInstance);
291 info = metadata.NeedsSerializationInfo ? new SerializationInfo(metadata.Type, new FormatterConverter()) : null;
293 if (metadata.MemberNames != null) {
294 for (int n=0; n<metadata.FieldCount; n++)
295 ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberNames[n], null, null);
297 for (int n=0; n<metadata.FieldCount; n++) {
298 if (metadata.MemberInfos [n] != null)
299 ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberInfos[n].Name, metadata.MemberInfos[n], null);
300 else if (BinaryCommon.IsPrimitive(metadata.MemberTypes[n])) {
301 // Since the member info is null, the type in this
302 // domain does not have this type. Even though we
303 // are not going to store the value, we will read
304 // it from the stream so that we can advance to the
306 ReadPrimitiveTypeValue (reader, metadata.MemberTypes[n]);
311 private void RegisterObject (long objectId, object objectInstance, SerializationInfo info, long parentObjectId, MemberInfo parentObjectMemeber, int[] indices)
313 if (parentObjectId == 0) indices = null;
315 if (!objectInstance.GetType().IsValueType || parentObjectId == 0)
316 _manager.RegisterObject (objectInstance, objectId, info, 0, null, null);
319 if (indices != null) indices = (int[])indices.Clone();
320 _manager.RegisterObject (objectInstance, objectId, info, parentObjectId, parentObjectMemeber, indices);
324 private void ReadStringIntance (BinaryReader reader, out long objectId, out object value)
326 objectId = (long) reader.ReadUInt32 ();
327 value = reader.ReadString ();
330 private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)
332 objectId = (long) reader.ReadUInt32 ();
336 int rank = reader.ReadInt32();
338 bool emptyDim = false;
339 int[] lengths = new int[rank];
340 for (int n=0; n<rank; n++)
342 lengths[n] = reader.ReadInt32();
343 if (lengths[n] == 0) emptyDim = true;
346 TypeTag code = (TypeTag) reader.ReadByte ();
347 Type elementType = ReadType (reader, code);
349 Array array = Array.CreateInstance (elementType, lengths);
357 int[] indices = new int[rank];
359 // Initialize indexes
360 for (int dim = rank-1; dim >= 0; dim--)
361 indices[dim] = array.GetLowerBound (dim);
366 ReadValue (reader, array, objectId, null, elementType, null, null, indices);
368 for (int dim = array.Rank-1; dim >= 0; dim--)
371 if (indices[dim] > array.GetUpperBound (dim))
375 indices[dim] = array.GetLowerBound (dim);
376 continue; // Increment the next dimension's index
378 end = true; // That was the last dimension. Finished.
386 private object ReadBoxedPrimitiveTypeValue (BinaryReader reader)
388 Type type = ReadType (reader, TypeTag.PrimitiveType);
389 return ReadPrimitiveTypeValue (reader, type);
392 private void ReadArrayOfPrimitiveType (BinaryReader reader, out long objectId, out object val)
394 objectId = (long) reader.ReadUInt32 ();
395 int length = reader.ReadInt32 ();
396 Type elementType = ReadType (reader, TypeTag.PrimitiveType);
398 switch (Type.GetTypeCode (elementType))
400 case TypeCode.Boolean: {
401 bool[] arr = new bool [length];
402 for (int n = 0; n < length; n++) arr [n] = reader.ReadBoolean();
407 case TypeCode.Byte: {
408 byte[] arr = new byte [length];
410 while (pos < length) {
411 int nr = reader.Read (arr, pos, length - pos);
419 case TypeCode.Char: {
420 char[] arr = new char [length];
422 while (pos < length) {
423 int nr = reader.Read (arr, pos, length - pos);
431 case TypeCode.DateTime: {
432 DateTime[] arr = new DateTime [length];
433 for (int n = 0; n < length; n++) {
434 arr [n] = DateTime.FromBinary (reader.ReadInt64 ());
440 case TypeCode.Decimal: {
441 Decimal[] arr = new Decimal [length];
442 for (int n = 0; n < length; n++) arr [n] = reader.ReadDecimal();
447 case TypeCode.Double: {
448 Double[] arr = new Double [length];
450 BlockRead (reader, arr, 8);
452 for (int n = 0; n < length; n++) arr [n] = reader.ReadDouble();
457 case TypeCode.Int16: {
458 short[] arr = new short [length];
460 BlockRead (reader, arr, 2);
462 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt16();
467 case TypeCode.Int32: {
468 int[] arr = new int [length];
470 BlockRead (reader, arr, 4);
472 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt32();
477 case TypeCode.Int64: {
478 long[] arr = new long [length];
480 BlockRead (reader, arr, 8);
482 for (int n = 0; n < length; n++) arr [n] = reader.ReadInt64();
487 case TypeCode.SByte: {
488 sbyte[] arr = new sbyte [length];
490 BlockRead (reader, arr, 1);
492 for (int n = 0; n < length; n++) arr [n] = reader.ReadSByte();
497 case TypeCode.Single: {
498 float[] arr = new float [length];
500 BlockRead (reader, arr, 4);
502 for (int n = 0; n < length; n++) arr [n] = reader.ReadSingle();
507 case TypeCode.UInt16: {
508 ushort[] arr = new ushort [length];
510 BlockRead (reader, arr, 2);
512 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt16();
517 case TypeCode.UInt32: {
518 uint[] arr = new uint [length];
520 BlockRead (reader, arr, 4);
522 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt32();
527 case TypeCode.UInt64: {
528 ulong[] arr = new ulong [length];
530 BlockRead (reader, arr, 8);
532 for (int n = 0; n < length; n++) arr [n] = reader.ReadUInt64();
537 case TypeCode.String: {
538 string[] arr = new string [length];
539 for (int n = 0; n < length; n++) arr [n] = reader.ReadString();
545 if (elementType == typeof(TimeSpan)) {
546 TimeSpan[] arr = new TimeSpan [length];
547 for (int n = 0; n < length; n++) arr [n] = new TimeSpan (reader.ReadInt64 ());
551 throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
557 private void BlockRead (BinaryReader reader, Array array, int dataSize)
559 int totalSize = Buffer.ByteLength (array);
561 if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
562 arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
565 while (totalSize > 0) {
566 int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
569 int nr = reader.Read (arrayBuffer, ap, size - ap);
574 if (!BitConverter.IsLittleEndian && dataSize > 1)
575 BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
577 Buffer.BlockCopy (arrayBuffer, 0, array, pos, size);
584 private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)
586 ReadSimpleArray (reader, typeof (object), out objectId, out array);
589 private void ReadArrayOfString (BinaryReader reader, out long objectId, out object array)
591 ReadSimpleArray (reader, typeof (string), out objectId, out array);
594 private void ReadSimpleArray (BinaryReader reader, Type elementType, out long objectId, out object val)
596 objectId = (long) reader.ReadUInt32 ();
597 int length = reader.ReadInt32 ();
598 int[] indices = new int[1];
600 Array array = Array.CreateInstance (elementType, length);
601 for (int n = 0; n < length; n++)
604 ReadValue (reader, array, objectId, null, elementType, null, null, indices);
610 private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject, bool hasTypeInfo)
612 TypeMetadata metadata = new TypeMetadata();
614 string className = reader.ReadString ();
615 int fieldCount = reader.ReadInt32 ();
617 Type[] types = new Type[fieldCount];
618 string[] names = new string[fieldCount];
620 for (int n=0; n<fieldCount; n++)
621 names [n] = reader.ReadString ();
625 TypeTag[] codes = new TypeTag[fieldCount];
627 for (int n=0; n<fieldCount; n++)
628 codes [n] = (TypeTag) reader.ReadByte ();
630 for (int n=0; n<fieldCount; n++) {
631 Type t = ReadType (reader, codes[n], false);
632 // The field's type could not be resolved: assume it is an object.
641 if (!isRuntimeObject)
643 long assemblyId = (long)reader.ReadUInt32();
644 metadata.Type = GetDeserializationType (assemblyId, className);
647 metadata.Type = Type.GetType (className, true);
649 metadata.MemberTypes = types;
650 metadata.MemberNames = names;
651 metadata.FieldCount = names.Length;
653 // Now check if this objects needs a SerializationInfo struct for deserialziation.
654 // SerializationInfo is needed if the object has to be deserialized using
655 // a serialization surrogate, or if it implements ISerializable.
657 if (_surrogateSelector != null)
659 // check if the surrogate selector handles objects of the given type.
660 ISurrogateSelector selector;
661 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.Type, _context, out selector);
662 metadata.NeedsSerializationInfo = (surrogate != null);
665 if (!metadata.NeedsSerializationInfo)
667 // Check if the object is marked with the Serializable attribute
669 if (!metadata.Type.IsSerializable)
670 throw new SerializationException("Serializable objects must be marked with the Serializable attribute");
672 metadata.NeedsSerializationInfo = typeof (ISerializable).IsAssignableFrom (metadata.Type);
673 if (!metadata.NeedsSerializationInfo)
675 metadata.MemberInfos = new MemberInfo [fieldCount];
676 for (int n=0; n<fieldCount; n++)
678 FieldInfo field = null;
679 string memberName = names[n];
681 int i = memberName.IndexOf ('+');
683 string baseTypeName = names[n].Substring (0,i);
684 memberName = names[n].Substring (i+1);
685 Type t = metadata.Type.BaseType;
687 if (t.Name == baseTypeName) {
688 field = t.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
696 field = metadata.Type.GetField (memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
699 metadata.MemberInfos [n] = field;
702 types [n] = field.FieldType;
705 metadata.MemberNames = null; // Info now in MemberInfos
709 // Registers the type's metadata so it can be reused later if
710 // a RefTypeObject element is found
712 if (!_typeMetadataCache.ContainsKey (metadata.Type))
713 _typeMetadataCache [metadata.Type] = metadata;
718 // Called for primitive types
719 static bool IsGeneric (MemberInfo minfo)
725 switch (minfo.MemberType) {
726 case MemberTypes.Field:
727 mtype = ((FieldInfo) minfo).FieldType;
730 throw new NotSupportedException ("Not supported: " + minfo.MemberType);
732 return (mtype != null && mtype.IsGenericType);
735 private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, MemberInfo memberInfo, int[] indices)
737 // Reads a value from the stream and assigns it to the member of an object
741 if (BinaryCommon.IsPrimitive (valueType) && !IsGeneric (memberInfo))
743 val = ReadPrimitiveTypeValue (reader, valueType);
744 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
750 BinaryElement element = (BinaryElement)reader.ReadByte ();
752 if (element == BinaryElement.ObjectReference)
754 // Just read the id of the referred object and record a fixup
755 long childObjectId = (long) reader.ReadUInt32();
756 RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);
761 SerializationInfo objectInfo;
763 ReadObject (element, reader, out objectId, out val, out objectInfo);
765 // There are two cases where the object cannot be assigned to the parent
766 // and a fixup must be used:
767 // 1) When what has been read is not an object, but an id of an object that
768 // has not been read yet (an object reference). This is managed in the
769 // previous block of code.
770 // 2) When the read object is a value type object. Value type fields hold
771 // copies of objects, not references. Thus, if the value object that
772 // has been read has pending fixups, those fixups would be made to the
773 // boxed copy in the ObjectManager, and not in the required object instance
775 // First of all register the fixup, and then the object. ObjectManager is more
776 // efficient if done in this order
778 bool hasFixup = false;
781 if (val.GetType().IsValueType)
783 RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);
787 // Register the value
789 if (info == null && !(parentObject is Array))
790 RegisterObject (objectId, val, objectInfo, parentObjectId, memberInfo, null);
792 RegisterObject (objectId, val, objectInfo, parentObjectId, null, indices);
794 // Assign the value to the parent object, unless there is a fixup
797 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);
800 private void SetObjectValue (object parentObject, string fieldName, MemberInfo memberInfo, SerializationInfo info, object value, Type valueType, int[] indices)
802 if (value is IObjectReference)
803 value = ((IObjectReference)value).GetRealObject (_context);
805 if (parentObject is Array)
807 if (value is ArrayNullFiller)
809 // It must be a single dimension array of objects.
810 // Just increase the index. Elements are null by default.
811 int count = ((ArrayNullFiller)value).NullCount;
812 indices[0] += count - 1;
815 ((Array)parentObject).SetValue (value, indices);
817 else if (info != null) {
818 info.AddValue (fieldName, value, valueType);
821 if (memberInfo is FieldInfo)
822 ((FieldInfo)memberInfo).SetValue (parentObject, value);
824 ((PropertyInfo)memberInfo).SetValue (parentObject, value, null);
828 private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, MemberInfo memberInfo, int[] indices)
831 _manager.RecordDelayedFixup (parentObjectId, fieldName, childObjectId);
833 else if (parentObject is Array) {
834 if (indices.Length == 1)
835 _manager.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);
837 _manager.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);
840 _manager.RecordFixup (parentObjectId, memberInfo, childObjectId);
844 private Type GetDeserializationType (long assemblyId, string className)
846 return GetDeserializationType (assemblyId, className, true);
849 private Type GetDeserializationType (long assemblyId, string className, bool throwOnError)
852 string assemblyName = (string)_registeredAssemblies[assemblyId];
854 if (_binder != null) {
855 t = _binder.BindToType (assemblyName, className);
862 assembly = Assembly.Load (assemblyName);
863 } catch (Exception ex) {
866 throw new SerializationException (String.Format ("Couldn't find assembly '{0}'", assemblyName), ex);
869 t = assembly.GetType (className);
876 throw new SerializationException (String.Format ("Couldn't find type '{0}' in assembly '{1}'", className, assemblyName));
879 public Type ReadType (BinaryReader reader, TypeTag code)
881 return ReadType (reader, code, true);
884 public Type ReadType (BinaryReader reader, TypeTag code, bool throwOnError)
888 case TypeTag.PrimitiveType:
889 return BinaryCommon.GetTypeFromCode (reader.ReadByte());
892 return typeof(string);
894 case TypeTag.ObjectType:
895 return typeof(object);
897 case TypeTag.RuntimeType:
899 string name = reader.ReadString ();
900 // map MS.NET's System.RuntimeType to System.MonoType
901 if (_context.State == StreamingContextStates.Remoting)
902 if (name == "System.RuntimeType")
903 return typeof (MonoType);
904 else if (name == "System.RuntimeType[]")
905 return typeof (MonoType[]);
906 Type t = Type.GetType (name);
910 throw new SerializationException (String.Format ("Could not find type '{0}'.", name));
913 case TypeTag.GenericType:
915 string name = reader.ReadString ();
916 long asmid = (long) reader.ReadUInt32();
917 return GetDeserializationType (asmid, name, throwOnError);
920 case TypeTag.ArrayOfObject:
921 return typeof(object[]);
923 case TypeTag.ArrayOfString:
924 return typeof(string[]);
926 case TypeTag.ArrayOfPrimitiveType:
927 Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());
928 return Type.GetType(elementType.FullName + "[]");
931 throw new NotSupportedException ("Unknow type tag");
935 public static object ReadPrimitiveTypeValue (BinaryReader reader, Type type)
937 if (type == null) return null;
939 switch (Type.GetTypeCode (type))
941 case TypeCode.Boolean:
942 return reader.ReadBoolean();
945 return reader.ReadByte();
948 return reader.ReadChar();
950 case TypeCode.DateTime:
951 return DateTime.FromBinary (reader.ReadInt64());
953 case TypeCode.Decimal:
954 return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);
956 case TypeCode.Double:
957 return reader.ReadDouble();
960 return reader.ReadInt16();
963 return reader.ReadInt32();
966 return reader.ReadInt64();
969 return reader.ReadSByte();
971 case TypeCode.Single:
972 return reader.ReadSingle();
974 case TypeCode.UInt16:
975 return reader.ReadUInt16();
977 case TypeCode.UInt32:
978 return reader.ReadUInt32();
980 case TypeCode.UInt64:
981 return reader.ReadUInt64();
983 case TypeCode.String:
984 return reader.ReadString();
987 if (type == typeof(TimeSpan))
988 return new TimeSpan (reader.ReadInt64 ());
990 throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);