ObjectReader.cs 22 KB

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