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