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