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