* MessageFormatter.cs: Serialize Args, not OutArgs, like in MS.NET.
[mono.git] / mcs / class / corlib / System.Runtime.Serialization.Formatters.Binary / ObjectReader.cs
1 // ObjectReader.cs\r
2 //\r
3 // Author:\r
4 //   Lluis Sanchez Gual (lluis@ideary.com)\r
5 //   Patrik Torstensson\r
6 //\r
7 // (C) 2003 Lluis Sanchez Gual\r
8 \r
9 using System;\r
10 using System.Runtime.Serialization;\r
11 using System.IO;\r
12 using System.Collections;\r
13 using System.Reflection;\r
14 using System.Runtime.Remoting.Messaging;\r
15 using System.Globalization;\r
16 \r
17 namespace System.Runtime.Serialization.Formatters.Binary\r
18 {\r
19         internal class ObjectReader\r
20         {\r
21                 BinaryFormatter _formatter;\r
22                 ISurrogateSelector _surrogateSelector;\r
23                 StreamingContext _context;\r
24                 SerializationBinder _binder;\r
25                 \r
26 #if NET_1_1\r
27                 TypeFilterLevel _filterLevel;\r
28 #endif\r
29 \r
30                 ObjectManager _manager;\r
31                 Hashtable _registeredAssemblies = new Hashtable();\r
32                 Hashtable _typeMetadataCache = new Hashtable();\r
33 \r
34                 object _lastObject = null;\r
35                 long _lastObjectID = 0;\r
36                 long _rootObjectID = 0;\r
37 \r
38                 class TypeMetadata\r
39                 {\r
40                         public Type Type;\r
41                         public Type[] MemberTypes;\r
42                         public string[] MemberNames;\r
43                         public MemberInfo[] MemberInfos;\r
44                         public int FieldCount;\r
45                         public bool NeedsSerializationInfo;\r
46                 }\r
47 \r
48                 class ArrayNullFiller\r
49                 {\r
50                         public ArrayNullFiller(int count) { NullCount = count; }\r
51                         public int NullCount;\r
52                 }\r
53 \r
54                 public ObjectReader (BinaryFormatter formatter)\r
55                 {\r
56                         _formatter = formatter;\r
57                         _surrogateSelector = formatter.SurrogateSelector;\r
58                         _context = formatter.Context;\r
59                         _binder = formatter.Binder;\r
60                         _manager = new ObjectManager (_surrogateSelector, _context);\r
61                         \r
62 #if NET_1_1\r
63                         _filterLevel = formatter.FilterLevel;\r
64 #endif\r
65                 }\r
66 \r
67                 public void ReadObjectGraph (BinaryReader reader, bool readHeaders, out object result, out Header[] headers)\r
68                 {\r
69                         headers = null;\r
70 \r
71                         // Reads the objects. The first object in the stream is the\r
72                         // root object.\r
73 \r
74                         while (ReadNextObject (reader))\r
75                         {\r
76                                 if (readHeaders && (headers == null))\r
77                                         headers = (Header[])CurrentObject;\r
78                                 else\r
79                                         if (_rootObjectID == 0) _rootObjectID = _lastObjectID;\r
80                         }\r
81 \r
82                         result = _manager.GetObject (_rootObjectID);\r
83                 }\r
84 \r
85                 public bool ReadNextObject (BinaryReader reader)\r
86                 {\r
87                         BinaryElement element = (BinaryElement)reader.ReadByte ();\r
88                         if (element == BinaryElement.End)\r
89                         {\r
90                                 _manager.DoFixups();\r
91 \r
92                                 _manager.RaiseDeserializationEvent();\r
93                                 return false;\r
94                         }\r
95 \r
96                         SerializationInfo info;\r
97                         long objectId;\r
98 \r
99                         ReadObject (element, reader, out objectId, out _lastObject, out info);\r
100 \r
101                         if (objectId != 0) {\r
102                                 RegisterObject (objectId, _lastObject, info, 0, null, null);\r
103                                 _lastObjectID = objectId;               \r
104                         }\r
105         \r
106                         return true;\r
107                 }\r
108 \r
109                 public object CurrentObject\r
110                 {\r
111                         get { return _lastObject; }\r
112                 }\r
113 \r
114                 // Reads an object from the stream. The object is registered in the ObjectManager.\r
115                 // The result can be either the object instance\r
116                 // or the id of the object (when what is found in the stream is an object reference).\r
117                 // If an object instance is read, the objectId is set to 0.\r
118                 \r
119                 private void ReadObject (BinaryElement element, BinaryReader reader, out long objectId, out object value, out SerializationInfo info)\r
120                 {\r
121                         switch (element)\r
122                         {\r
123                                 case BinaryElement.RefTypeObject:\r
124                                         ReadRefTypeObjectInstance (reader, out objectId, out value, out info);\r
125                                         break;\r
126 \r
127                                 case BinaryElement.RuntimeObject:\r
128                                         ReadObjectInstance (reader, true, out objectId, out value, out info);\r
129                                         break;\r
130 \r
131                                 case BinaryElement.ExternalObject:\r
132                                         ReadObjectInstance (reader, false, out objectId, out value, out info);\r
133                                         break;\r
134 \r
135                                 case BinaryElement.String:\r
136                                         info = null;\r
137                                         ReadStringIntance (reader, out objectId, out value);\r
138                                         break;\r
139 \r
140                                 case BinaryElement.GenericArray:\r
141                                         info = null;\r
142                                         ReadGenericArray (reader, out objectId, out value);\r
143                                         break;\r
144 \r
145 \r
146                                 case BinaryElement.BoxedPrimitiveTypeValue:\r
147                                         value = ReadBoxedPrimitiveTypeValue (reader);\r
148                                         objectId = 0;\r
149                                         info = null;\r
150                                         break;\r
151 \r
152                                 case BinaryElement.NullValue:\r
153                                         value = null;\r
154                                         objectId = 0;\r
155                                         info = null;\r
156                                         break;\r
157 \r
158                                 case BinaryElement.Assembly:\r
159                                         ReadAssembly (reader);\r
160                                         ReadObject ((BinaryElement)reader.ReadByte (), reader, out objectId, out value, out info);\r
161                                         break;\r
162 \r
163                                 case BinaryElement.ArrayFiller8b:\r
164                                         value = new ArrayNullFiller(reader.ReadByte());\r
165                                         objectId = 0;\r
166                                         info = null;\r
167                                         break;\r
168 \r
169                                 case BinaryElement.ArrayFiller32b:\r
170                                         value = new ArrayNullFiller(reader.ReadInt32());\r
171                                         objectId = 0;\r
172                                         info = null;\r
173                                         break;\r
174 \r
175                                 case BinaryElement.ArrayOfPrimitiveType:\r
176                                         ReadArrayOfPrimitiveType (reader, out objectId, out value);\r
177                                         info = null;\r
178                                         break;\r
179 \r
180                                 case BinaryElement.ArrayOfObject:\r
181                                         ReadArrayOfObject (reader, out objectId, out value);\r
182                                         info = null;\r
183                                         break;\r
184 \r
185                                 case BinaryElement.ArrayOfString:\r
186                                         ReadArrayOfString (reader, out objectId, out value);\r
187                                         info = null;\r
188                                         break;\r
189 \r
190                                 default:\r
191                                         throw new SerializationException ("Unexpected binary element: " + (int)element);\r
192                         }\r
193                 }\r
194 \r
195                 private void ReadAssembly (BinaryReader reader)\r
196                 {\r
197                         long id = (long) reader.ReadUInt32 ();\r
198                         string assemblyName = reader.ReadString ();\r
199                         _registeredAssemblies [id] = assemblyName;\r
200                 }\r
201 \r
202                 private void ReadObjectInstance (BinaryReader reader, bool isRuntimeObject, out long objectId, out object value, out SerializationInfo info)\r
203                 {\r
204                         objectId = (long) reader.ReadUInt32 ();\r
205 \r
206                         TypeMetadata metadata = ReadTypeMetadata (reader, isRuntimeObject);\r
207                         ReadObjectContent (reader, metadata, objectId, out value, out info);\r
208                 }\r
209 \r
210                 private void ReadRefTypeObjectInstance (BinaryReader reader, out long objectId, out object value, out SerializationInfo info)\r
211                 {\r
212                         objectId = (long) reader.ReadUInt32 ();\r
213                         long refTypeObjectId = (long) reader.ReadUInt32 ();\r
214 \r
215                         // Gets the type of the referred object and its metadata\r
216 \r
217                         object refObj = _manager.GetObject (refTypeObjectId);\r
218                         if (refObj == null) throw new SerializationException ("Invalid binary format");\r
219                         TypeMetadata metadata = (TypeMetadata)_typeMetadataCache [refObj.GetType()];\r
220 \r
221                         ReadObjectContent (reader, metadata, objectId, out value, out info);\r
222                 }\r
223 \r
224                 private void ReadObjectContent (BinaryReader reader, TypeMetadata metadata, long objectId, out object objectInstance, out SerializationInfo info)\r
225                 {\r
226 #if NET_1_1\r
227                         if (_filterLevel == TypeFilterLevel.Low)\r
228                                 objectInstance = FormatterServices.GetSafeUninitializedObject (metadata.Type);\r
229                         else\r
230 #endif\r
231                                 objectInstance = FormatterServices.GetUninitializedObject (metadata.Type);\r
232                                 \r
233                         info = metadata.NeedsSerializationInfo ? new SerializationInfo(metadata.Type, new FormatterConverter()) : null;\r
234 \r
235                         if (metadata.MemberNames != null)\r
236                                 for (int n=0; n<metadata.FieldCount; n++)\r
237                                         ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberNames[n], null, null);\r
238                         else\r
239                                 for (int n=0; n<metadata.FieldCount; n++)\r
240                                         ReadValue (reader, objectInstance, objectId, info, metadata.MemberTypes[n], metadata.MemberInfos[n].Name, metadata.MemberInfos[n], null);\r
241                 }\r
242 \r
243                 private void RegisterObject (long objectId, object objectInstance, SerializationInfo info, long parentObjectId, MemberInfo parentObjectMemeber, int[] indices)\r
244                 {\r
245                         if (parentObjectId == 0) indices = null;\r
246 \r
247                         if (!objectInstance.GetType().IsValueType || parentObjectId == 0)\r
248                                 _manager.RegisterObject (objectInstance, objectId, info, 0, null, null);\r
249                         else\r
250                         {\r
251                                 if (indices != null) indices = (int[])indices.Clone();\r
252                                 _manager.RegisterObject (objectInstance, objectId, info, parentObjectId, parentObjectMemeber, indices);\r
253                         }\r
254                 }\r
255 \r
256                 private void ReadStringIntance (BinaryReader reader, out long objectId, out object value)\r
257                 {\r
258                         objectId = (long) reader.ReadUInt32 ();\r
259                         value = reader.ReadString ();\r
260                 }\r
261 \r
262                 private void ReadGenericArray (BinaryReader reader, out long objectId, out object val)\r
263                 {\r
264                         objectId = (long) reader.ReadUInt32 ();\r
265                         ArrayStructure structure = (ArrayStructure) reader.ReadByte();\r
266 \r
267                         int rank = reader.ReadInt32();\r
268 \r
269                         bool emptyDim = false;\r
270                         int[] lengths = new int[rank];\r
271                         for (int n=0; n<rank; n++)\r
272                         {\r
273                                 lengths[n] = reader.ReadInt32();\r
274                                 if (lengths[n] == 0) emptyDim = true;\r
275                         }\r
276 \r
277                         TypeTag code = (TypeTag) reader.ReadByte ();\r
278                         Type elementType = ReadType (reader, code);\r
279 \r
280                         Array array = Array.CreateInstance (elementType, lengths);\r
281 \r
282                         if (emptyDim) \r
283                         { \r
284                                 val = array;\r
285                                 return;\r
286                         }\r
287 \r
288                         int[] indices = new int[rank];\r
289 \r
290                         // Initialize indexes\r
291                         for (int dim = rank-1; dim >= 0; dim--)\r
292                                 indices[dim] = array.GetLowerBound (dim);\r
293 \r
294                         bool end = false;\r
295                         while (!end)\r
296                         {\r
297                                 ReadValue (reader, array, objectId, null, elementType, null, null, indices);\r
298 \r
299                                 for (int dim = array.Rank-1; dim >= 0; dim--)\r
300                                 {\r
301                                         indices[dim]++;\r
302                                         if (indices[dim] > array.GetUpperBound (dim))\r
303                                         {\r
304                                                 if (dim > 0) \r
305                                                 {\r
306                                                         indices[dim] = array.GetLowerBound (dim);\r
307                                                         continue;       // Increment the next dimension's index\r
308                                                 }\r
309                                                 end = true;     // That was the last dimension. Finished.\r
310                                         }\r
311                                         break;\r
312                                 }\r
313                         }\r
314                         val = array;\r
315                 }\r
316 \r
317                 private object ReadBoxedPrimitiveTypeValue (BinaryReader reader)\r
318                 {\r
319                         Type type = ReadType (reader, TypeTag.PrimitiveType);\r
320                         return ReadPrimitiveTypeValue (reader, type);\r
321                 }\r
322 \r
323                 private void ReadArrayOfPrimitiveType (BinaryReader reader, out long objectId, out object val)\r
324                 {\r
325                         objectId = (long) reader.ReadUInt32 ();\r
326                         int length = reader.ReadInt32 ();\r
327                         Type elementType = ReadType (reader, TypeTag.PrimitiveType);\r
328 \r
329                         Array array = Array.CreateInstance (elementType, length);\r
330                         for (int n = 0; n < length; n++)\r
331                                 array.SetValue (ReadPrimitiveTypeValue (reader, elementType), n);\r
332 \r
333                         val = array;\r
334                 }\r
335 \r
336                 private void ReadArrayOfObject (BinaryReader reader, out long objectId, out object array)\r
337                 {\r
338                         ReadSimpleArray (reader, typeof (object), out objectId, out array);\r
339                 }\r
340                 \r
341                 private void ReadArrayOfString (BinaryReader reader, out long objectId, out object array)\r
342                 {\r
343                         ReadSimpleArray (reader, typeof (string), out objectId, out array);\r
344                 }\r
345 \r
346                 private void ReadSimpleArray (BinaryReader reader, Type elementType, out long objectId, out object val)\r
347                 {\r
348                         objectId = (long) reader.ReadUInt32 ();\r
349                         int length = reader.ReadInt32 ();\r
350                         int[] indices = new int[1];\r
351 \r
352                         Array array = Array.CreateInstance (elementType, length);\r
353                         for (int n = 0; n < length; n++)\r
354                         {\r
355                                 indices[0] = n;\r
356                                 ReadValue (reader, array, objectId, null, elementType, null, null, indices);\r
357                                 n = indices[0];\r
358                         }\r
359                         val = array;\r
360                 }\r
361 \r
362                 private TypeMetadata ReadTypeMetadata (BinaryReader reader, bool isRuntimeObject)\r
363                 {\r
364                         TypeMetadata metadata = new TypeMetadata();\r
365 \r
366                         string className = reader.ReadString ();\r
367                         int fieldCount = reader.ReadInt32 ();\r
368 \r
369                         Type[] types = new Type[fieldCount];\r
370                         string[] names = new string[fieldCount];\r
371 \r
372                         TypeTag[] codes = new TypeTag[fieldCount];\r
373 \r
374                         for (int n=0; n<fieldCount; n++)\r
375                                 names [n] = reader.ReadString ();\r
376 \r
377                         for (int n=0; n<fieldCount; n++)\r
378                                 codes [n] = (TypeTag) reader.ReadByte ();\r
379 \r
380                         for (int n=0; n<fieldCount; n++)\r
381                                 types [n] = ReadType (reader, codes[n]);\r
382 \r
383                         // Gets the type\r
384 \r
385                         if (!isRuntimeObject) \r
386                         {\r
387                                 long assemblyId = (long)reader.ReadUInt32();\r
388                                 metadata.Type = GetDeserializationType (assemblyId, className);\r
389                         }\r
390                         else\r
391                                 metadata.Type = Type.GetType (className, true);\r
392 \r
393                         metadata.MemberTypes = types;\r
394                         metadata.MemberNames = names;\r
395                         metadata.FieldCount = names.Length;\r
396 \r
397                         // Now check if this objects needs a SerializationInfo struct for deserialziation.\r
398                         // SerializationInfo is needed if the object has to be deserialized using\r
399                         // a serialization surrogate, or if it implements ISerializable.\r
400 \r
401                         if (_surrogateSelector != null)\r
402                         {\r
403                                 // check if the surrogate selector handles objects of the given type. \r
404                                 ISurrogateSelector selector;\r
405                                 ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (metadata.Type, _context, out selector);\r
406                                 metadata.NeedsSerializationInfo = (surrogate != null);\r
407                         }\r
408 \r
409                         if (!metadata.NeedsSerializationInfo)\r
410                         {\r
411                                 // Check if the object is marked with the Serializable attribute\r
412 \r
413                                 if (!metadata.Type.IsSerializable)\r
414                                         throw new SerializationException("Serializable objects must be marked with the Serializable attribute");\r
415 \r
416                                 metadata.NeedsSerializationInfo = (metadata.Type.GetInterface ("ISerializable") != null);\r
417                                 if (!metadata.NeedsSerializationInfo)\r
418                                 {\r
419                                         metadata.MemberInfos = new MemberInfo [fieldCount];\r
420                                         for (int n=0; n<fieldCount; n++)\r
421                                         {\r
422                                                 MemberInfo[] members = null;\r
423                                                 string memberName = names[n];\r
424                                                 \r
425                                                 int i = memberName.IndexOf ('+');\r
426                                                 if (i != -1) {\r
427                                                         string baseTypeName = names[n].Substring (0,i);\r
428                                                         memberName = names[n].Substring (i+1);\r
429                                                         Type t = metadata.Type.BaseType;\r
430                                                         while (t != null) {\r
431                                                                 if (t.Name == baseTypeName) {\r
432                                                                         members = t.GetMember (memberName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
433                                                                         break;\r
434                                                                 }\r
435                                                                 else\r
436                                                                         t = t.BaseType;\r
437                                                         }\r
438                                                 }\r
439                                                 else\r
440                                                         members = metadata.Type.GetMember (memberName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\r
441                                                         \r
442                                                 if (members == null || members.Length == 0) throw new SerializationException ("Field \"" + names[n] + "\" not found in class " + metadata.Type.FullName);\r
443                                                 if (members.Length > 1) throw new SerializationException ("There are two public members named \"" + names[n] + "\" in the class hirearchy of " + metadata.Type.FullName);\r
444                                                 metadata.MemberInfos [n] = members[0];\r
445                                         }\r
446                                         metadata.MemberNames = null;    // Info now in MemberInfos\r
447                                 }\r
448                         }\r
449 \r
450                         // Registers the type's metadata so it can be reused later if\r
451                         // a RefTypeObject element is found\r
452 \r
453                         if (!_typeMetadataCache.ContainsKey (metadata.Type))\r
454                                 _typeMetadataCache [metadata.Type] = metadata;\r
455 \r
456                         return metadata;\r
457                 }\r
458 \r
459 \r
460                 private void ReadValue (BinaryReader reader, object parentObject, long parentObjectId, SerializationInfo info, Type valueType, string fieldName, MemberInfo memberInfo, int[] indices)\r
461                 {\r
462                         // Reads a value from the stream and assigns it to the member of an object\r
463 \r
464                         object val;\r
465 \r
466                         if (BinaryCommon.IsPrimitive (valueType))\r
467                         {\r
468                                 val = ReadPrimitiveTypeValue (reader, valueType);\r
469                                 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);\r
470                                 return;\r
471                         }\r
472 \r
473                         // Gets the object\r
474 \r
475                         BinaryElement element = (BinaryElement)reader.ReadByte ();\r
476 \r
477                         if (element == BinaryElement.ObjectReference)\r
478                         {\r
479                                 // Just read the id of the referred object and record a fixup\r
480                                 long childObjectId = (long) reader.ReadUInt32();\r
481                                 RecordFixup (parentObjectId, childObjectId, parentObject, info, fieldName, memberInfo, indices);\r
482                                 return;\r
483                         }\r
484 \r
485                         long objectId;\r
486                         SerializationInfo objectInfo;\r
487 \r
488                         ReadObject (element, reader, out objectId, out val, out objectInfo);\r
489 \r
490                         // There are two cases where the object cannot be assigned to the parent\r
491                         // and a fixup must be used:\r
492                         //  1) When what has been read is not an object, but an id of an object that\r
493                         //     has not been read yet (an object reference). This is managed in the\r
494                         //     previous block of code.\r
495                         //  2) When the read object is a value type object. Value type fields hold\r
496                         //     copies of objects, not references. Thus, if the value object that\r
497                         //     has been read has pending fixups, those fixups would be made to the\r
498                         //     boxed copy in the ObjectManager, and not in the required object instance\r
499 \r
500                         // First of all register the fixup, and then the object. ObjectManager is more\r
501                         // efficient if done in this order\r
502 \r
503                         bool hasFixup = false;\r
504                         if (objectId != 0)\r
505                         {\r
506                                 if (val.GetType().IsValueType)\r
507                                 {\r
508                                         RecordFixup (parentObjectId, objectId, parentObject, info, fieldName, memberInfo, indices);\r
509                                         hasFixup = true;\r
510                                 }\r
511 \r
512                                 // Register the value\r
513 \r
514                                 if (info == null && !(parentObject is Array))\r
515                                         RegisterObject (objectId, val, objectInfo, parentObjectId, memberInfo, null);\r
516                                 else\r
517                                         RegisterObject (objectId, val, objectInfo, parentObjectId, null, indices);\r
518                         }\r
519                         // Assign the value to the parent object, unless there is a fixup\r
520                         \r
521                         if (!hasFixup) \r
522                                 SetObjectValue (parentObject, fieldName, memberInfo, info, val, valueType, indices);\r
523                 }\r
524 \r
525                 private void SetObjectValue (object parentObject, string fieldName, MemberInfo memberInfo, SerializationInfo info, object value, Type valueType, int[] indices)\r
526                 {\r
527                         if (value is IObjectReference)\r
528                                 value = ((IObjectReference)value).GetRealObject (_context);\r
529 \r
530                         if (parentObject is Array) \r
531                         {\r
532                                 if (value is ArrayNullFiller) \r
533                                 {\r
534                                         // It must be a single dimension array of objects.\r
535                                         // Just increase the index. Elements are null by default.\r
536                                         int count = ((ArrayNullFiller)value).NullCount;\r
537                                         indices[0] += count - 1;\r
538                                 }\r
539                                 else\r
540                                         ((Array)parentObject).SetValue (value, indices);\r
541                         }\r
542                         else if (info != null) {\r
543                                 info.AddValue (fieldName, value, valueType);\r
544                         }\r
545                         else {\r
546                                 if (memberInfo is FieldInfo)\r
547                                         ((FieldInfo)memberInfo).SetValue (parentObject, value);\r
548                                 else\r
549                                         ((PropertyInfo)memberInfo).SetValue (parentObject, value, null);\r
550                         }\r
551                 }\r
552 \r
553                 private void RecordFixup (long parentObjectId, long childObjectId, object parentObject, SerializationInfo info, string fieldName, MemberInfo memberInfo, int[] indices)\r
554                 {\r
555                         if (info != null) {\r
556                                 _manager.RecordDelayedFixup (parentObjectId, fieldName, childObjectId);\r
557                         }\r
558                         else if (parentObject is Array) {\r
559                                 if (indices.Length == 1)\r
560                                         _manager.RecordArrayElementFixup (parentObjectId, indices[0], childObjectId);\r
561                                 else\r
562                                         _manager.RecordArrayElementFixup (parentObjectId, (int[])indices.Clone(), childObjectId);\r
563                         }\r
564                         else {\r
565                                 _manager.RecordFixup (parentObjectId, memberInfo, childObjectId);\r
566                         }\r
567                 }\r
568 \r
569                 private Type GetDeserializationType (long assemblyId, string className)\r
570                 {\r
571                         string assemblyName = (string)_registeredAssemblies[assemblyId];\r
572 \r
573                         if (_binder == null)\r
574                         {\r
575                                 Assembly assembly = Assembly.Load (assemblyName);\r
576                                 return assembly.GetType (className, true);\r
577                         }\r
578                         else\r
579                                 return _binder.BindToType (assemblyName, className);\r
580                 }\r
581 \r
582                 public Type ReadType (BinaryReader reader, TypeTag code)\r
583                 {\r
584                         switch (code)\r
585                         {\r
586                                 case TypeTag.PrimitiveType:\r
587                                         return BinaryCommon.GetTypeFromCode (reader.ReadByte());\r
588 \r
589                                 case TypeTag.String:\r
590                                         return typeof(string);\r
591 \r
592                                 case TypeTag.ObjectType:\r
593                                         return typeof(object);\r
594 \r
595                                 case TypeTag.RuntimeType:\r
596                                 {\r
597                                         string name = reader.ReadString ();\r
598                                         return Type.GetType (name, true);\r
599                                 }\r
600 \r
601                                 case TypeTag.GenericType:\r
602                                 {\r
603                                         string name = reader.ReadString ();\r
604                                         long asmid = (long) reader.ReadUInt32();\r
605                                         return GetDeserializationType (asmid, name);\r
606                                 }\r
607 \r
608                                 case TypeTag.ArrayOfObject:\r
609                                         return typeof(object[]);\r
610 \r
611                                 case TypeTag.ArrayOfString:\r
612                                         return typeof(string[]);\r
613 \r
614                                 case TypeTag.ArrayOfPrimitiveType:\r
615                                         Type elementType = BinaryCommon.GetTypeFromCode (reader.ReadByte());\r
616                                         return Type.GetType(elementType.FullName + "[]");\r
617 \r
618                                 default:\r
619                                         throw new NotSupportedException ("Unknow type tag");\r
620                         }\r
621                 }\r
622                 \r
623                 public static object ReadPrimitiveTypeValue (BinaryReader reader, Type type)\r
624                 {\r
625                         if (type == null) return null;\r
626 \r
627                         switch (Type.GetTypeCode (type))\r
628                         {\r
629                                 case TypeCode.Boolean:\r
630                                         return reader.ReadBoolean();\r
631 \r
632                                 case TypeCode.Byte:\r
633                                         return reader.ReadByte();\r
634 \r
635                                 case TypeCode.Char:\r
636                                         return reader.ReadChar();\r
637 \r
638                                 case TypeCode.DateTime: \r
639                                         return new DateTime (reader.ReadInt64());\r
640 \r
641                                 case TypeCode.Decimal:\r
642                                         return Decimal.Parse (reader.ReadString(), CultureInfo.InvariantCulture);\r
643 \r
644                                 case TypeCode.Double:\r
645                                         return reader.ReadDouble();\r
646 \r
647                                 case TypeCode.Int16:\r
648                                         return reader.ReadInt16();\r
649 \r
650                                 case TypeCode.Int32:\r
651                                         return reader.ReadInt32();\r
652 \r
653                                 case TypeCode.Int64:\r
654                                         return reader.ReadInt64();\r
655 \r
656                                 case TypeCode.SByte:\r
657                                         return reader.ReadSByte();\r
658 \r
659                                 case TypeCode.Single:\r
660                                         return reader.ReadSingle();\r
661 \r
662                                 case TypeCode.UInt16:\r
663                                         return reader.ReadUInt16();\r
664 \r
665                                 case TypeCode.UInt32:\r
666                                         return reader.ReadUInt32();\r
667 \r
668                                 case TypeCode.UInt64:\r
669                                         return reader.ReadUInt64();\r
670 \r
671                                 case TypeCode.String:\r
672                                         return reader.ReadString();\r
673 \r
674                                 default:\r
675                                         if (type == typeof(TimeSpan))\r
676                                                 return new TimeSpan (reader.ReadInt64 ());\r
677                                         else\r
678                                                 throw new NotSupportedException ("Unsupported primitive type: " + type.FullName);\r
679                         }\r
680                 }\r
681         }\r
682 }