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