ObjectWriter.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. // ObjectWriter.cs
  2. //
  3. // Author:
  4. // Lluis Sanchez Gual ([email protected])
  5. //
  6. // (C) 2003 Lluis Sanchez Gual
  7. //
  8. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.IO;
  31. using System.Collections;
  32. using System.Runtime.Serialization;
  33. using System.Runtime.Remoting.Messaging;
  34. using System.Reflection;
  35. using System.Globalization;
  36. namespace System.Runtime.Serialization.Formatters.Binary
  37. {
  38. abstract class TypeMetadata
  39. {
  40. public TypeMetadata (Type instanceType)
  41. {
  42. InstanceType = instanceType;
  43. TypeAssembly = instanceType.Assembly;
  44. }
  45. public Assembly TypeAssembly;
  46. public Type InstanceType;
  47. public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer);
  48. public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer);
  49. public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data);
  50. public virtual bool IsCompatible (TypeMetadata other)
  51. {
  52. return true;
  53. }
  54. }
  55. class SerializableTypeMetadata: TypeMetadata
  56. {
  57. Type[] types;
  58. string[] names;
  59. public SerializableTypeMetadata (Type itype, SerializationInfo info): base (itype)
  60. {
  61. types = new Type [info.MemberCount];
  62. names = new string [info.MemberCount];
  63. SerializationInfoEnumerator e = info.GetEnumerator ();
  64. int n = 0;
  65. while (e.MoveNext ())
  66. {
  67. types[n] = e.ObjectType;
  68. names[n] = e.Name;
  69. n++;
  70. }
  71. if (info.FullTypeName != InstanceType.FullName || info.AssemblyName != TypeAssembly.FullName)
  72. {
  73. TypeAssembly = Assembly.Load (info.AssemblyName);
  74. InstanceType = TypeAssembly.GetType (info.FullTypeName);
  75. }
  76. }
  77. public override bool IsCompatible (TypeMetadata other)
  78. {
  79. if (!(other is SerializableTypeMetadata)) return false;
  80. SerializableTypeMetadata tm = (SerializableTypeMetadata)other;
  81. if (types.Length != tm.types.Length) return false;
  82. if (TypeAssembly != tm.TypeAssembly) return false;
  83. if (InstanceType != tm.InstanceType) return false;
  84. for (int n=0; n<types.Length; n++)
  85. {
  86. if (types[n] != tm.types[n]) return false;
  87. if (names[n] != tm.names[n]) return false;
  88. }
  89. return true;
  90. }
  91. public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
  92. {
  93. foreach (Type mtype in types)
  94. {
  95. Type type = mtype;
  96. while (type.IsArray)
  97. type = type.GetElementType();
  98. ow.WriteAssembly (writer, type.Assembly);
  99. }
  100. }
  101. public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer)
  102. {
  103. writer.Write (types.Length);
  104. // Names of fields
  105. foreach (string name in names)
  106. writer.Write (name);
  107. // Types of fields
  108. foreach (Type type in types)
  109. ObjectWriter.WriteTypeCode (writer, type);
  110. // Type specs of fields
  111. foreach (Type type in types)
  112. ow.WriteTypeSpec (writer, type);
  113. }
  114. public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
  115. {
  116. SerializationInfo info = (SerializationInfo) data;
  117. SerializationInfoEnumerator e = info.GetEnumerator ();
  118. while (e.MoveNext ())
  119. ow.WriteValue (writer, e.ObjectType, e.Value);
  120. }
  121. }
  122. class MemberTypeMetadata: TypeMetadata
  123. {
  124. MemberInfo[] members;
  125. public MemberTypeMetadata (Type type, StreamingContext context): base (type)
  126. {
  127. members = FormatterServices.GetSerializableMembers (type, context);
  128. }
  129. public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
  130. {
  131. foreach (FieldInfo field in members)
  132. {
  133. Type type = field.FieldType;
  134. while (type.IsArray)
  135. type = type.GetElementType();
  136. ow.WriteAssembly (writer, type.Assembly);
  137. }
  138. }
  139. public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer)
  140. {
  141. writer.Write (members.Length);
  142. // Names of fields
  143. foreach (FieldInfo field in members) {
  144. if (field.DeclaringType == InstanceType)
  145. writer.Write (field.Name);
  146. else
  147. writer.Write (field.DeclaringType.Name + "+" + field.Name);
  148. }
  149. // Types of fields
  150. foreach (FieldInfo field in members)
  151. ObjectWriter.WriteTypeCode (writer, field.FieldType);
  152. // Type specs of fields
  153. foreach (FieldInfo field in members)
  154. ow.WriteTypeSpec (writer, field.FieldType);
  155. }
  156. public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
  157. {
  158. object[] values = FormatterServices.GetObjectData (data, members);
  159. for (int n=0; n<values.Length; n++)
  160. ow.WriteValue (writer, ((FieldInfo)members[n]).FieldType, values[n]);
  161. }
  162. }
  163. internal class ObjectWriter
  164. {
  165. ObjectIDGenerator _idGenerator = new ObjectIDGenerator();
  166. Hashtable _cachedMetadata = new Hashtable();
  167. Queue _pendingObjects = new Queue();
  168. Hashtable _assemblyCache = new Hashtable();
  169. // Type metadata that can be shared with all serializers
  170. static Hashtable _cachedTypes = new Hashtable();
  171. internal static Assembly CorlibAssembly = typeof(string).Assembly;
  172. ISurrogateSelector _surrogateSelector;
  173. StreamingContext _context;
  174. FormatterAssemblyStyle _assemblyFormat;
  175. class MetadataReference
  176. {
  177. public TypeMetadata Metadata;
  178. public long ObjectID;
  179. public MetadataReference (TypeMetadata metadata, long id)
  180. {
  181. Metadata = metadata;
  182. ObjectID = id;
  183. }
  184. }
  185. public ObjectWriter (ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat)
  186. {
  187. _surrogateSelector = surrogateSelector;
  188. _context = context;
  189. _assemblyFormat = assemblyFormat;
  190. }
  191. public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)
  192. {
  193. _pendingObjects.Clear();
  194. if (headers != null) QueueObject (headers);
  195. QueueObject (obj);
  196. WriteQueuedObjects (writer);
  197. WriteSerializationEnd (writer);
  198. }
  199. public void QueueObject (object obj)
  200. {
  201. _pendingObjects.Enqueue (obj);
  202. }
  203. public void WriteQueuedObjects (BinaryWriter writer)
  204. {
  205. while (_pendingObjects.Count > 0)
  206. WriteObjectInstance (writer, _pendingObjects.Dequeue(), false);
  207. }
  208. public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject)
  209. {
  210. bool firstTime;
  211. long id;
  212. // If the object is a value type (not boxed) then there is no need
  213. // to register it in the id generator, because it won't have other
  214. // references to it
  215. if (isValueObject) id = _idGenerator.NextId;
  216. else id = _idGenerator.GetId (obj, out firstTime);
  217. if (obj is string) {
  218. WriteString (writer, id, (string)obj);
  219. }
  220. else if (obj is Array) {
  221. WriteArray (writer, id, (Array)obj);
  222. }
  223. else
  224. WriteObject (writer, id, obj);
  225. }
  226. public static void WriteSerializationEnd (BinaryWriter writer)
  227. {
  228. writer.Write ((byte) BinaryElement.End);
  229. }
  230. private void WriteObject (BinaryWriter writer, long id, object obj)
  231. {
  232. object data;
  233. TypeMetadata metadata;
  234. GetObjectData (obj, out metadata, out data);
  235. MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceType];
  236. if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata))
  237. {
  238. // An object of the same type has already been serialized
  239. // It is not necessary to write again type metadata
  240. writer.Write ((byte) BinaryElement.RefTypeObject);
  241. writer.Write ((int)id);
  242. writer.Write ((int)metadataReference.ObjectID);
  243. metadata.WriteObjectData (this, writer, data);
  244. return;
  245. }
  246. if (metadataReference == null)
  247. {
  248. metadataReference = new MetadataReference (metadata, id);
  249. _cachedMetadata [metadata.InstanceType] = metadataReference;
  250. }
  251. BinaryElement objectTag;
  252. int assemblyId;
  253. if (metadata.TypeAssembly == CorlibAssembly)
  254. {
  255. // A corlib type
  256. objectTag = BinaryElement.RuntimeObject;
  257. assemblyId = -1;
  258. }
  259. else
  260. {
  261. objectTag = BinaryElement.ExternalObject;
  262. assemblyId = WriteAssembly (writer, metadata.TypeAssembly);
  263. }
  264. // Registers the assemblies needed for each field
  265. // If there are assemblies that where not registered before this object,
  266. // write them now
  267. metadata.WriteAssemblies (this, writer);
  268. // Writes the object
  269. writer.Write ((byte) objectTag);
  270. writer.Write ((int)id);
  271. writer.Write (metadata.InstanceType.FullName);
  272. metadata.WriteTypeData (this, writer);
  273. if (assemblyId != -1) writer.Write (assemblyId);
  274. metadata.WriteObjectData (this, writer, data);
  275. }
  276. private void GetObjectData (object obj, out TypeMetadata metadata, out object data)
  277. {
  278. Type instanceType = obj.GetType();
  279. // Check if the formatter has a surrogate selector – if it does,
  280. // check if the surrogate selector handles objects of the given type.
  281. if (_surrogateSelector != null)
  282. {
  283. ISurrogateSelector selector;
  284. ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (instanceType, _context, out selector);
  285. if (surrogate != null)
  286. {
  287. SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
  288. surrogate.GetObjectData (obj, info, _context);
  289. metadata = new SerializableTypeMetadata (instanceType, info);
  290. data = info;
  291. return;
  292. }
  293. }
  294. // Check if the object is marked with the Serializable attribute
  295. BinaryCommon.CheckSerializable (instanceType, _surrogateSelector, _context);
  296. ISerializable ser = obj as ISerializable;
  297. if (ser != null)
  298. {
  299. SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
  300. ser.GetObjectData (info, _context);
  301. metadata = new SerializableTypeMetadata (instanceType, info);
  302. data = info;
  303. }
  304. else
  305. {
  306. data = obj;
  307. if (_context.Context != null)
  308. {
  309. // Don't cache metadata info when the Context property is not null sice
  310. // we can't control the number of possible contexts in this case
  311. metadata = new MemberTypeMetadata (instanceType, _context);
  312. return;
  313. }
  314. Hashtable typesTable;
  315. bool isNew = false;
  316. lock (_cachedTypes) {
  317. typesTable = (Hashtable) _cachedTypes [_context.State];
  318. if (typesTable == null) {
  319. typesTable = new Hashtable ();
  320. _cachedTypes [_context.State] = typesTable;
  321. isNew = true;
  322. }
  323. }
  324. metadata = null;
  325. lock (typesTable) {
  326. if (!isNew) {
  327. metadata = (TypeMetadata) typesTable [instanceType];
  328. }
  329. if (metadata == null) {
  330. metadata = CreateMemberTypeMetadata (instanceType);
  331. }
  332. typesTable [instanceType] = metadata;
  333. }
  334. }
  335. }
  336. TypeMetadata CreateMemberTypeMetadata (Type type)
  337. {
  338. if (!BinaryCommon.UseReflectionSerialization) {
  339. Type metaType = CodeGenerator.GenerateMetadataType (type, _context);
  340. return (TypeMetadata) Activator.CreateInstance (metaType);
  341. }
  342. else
  343. return new MemberTypeMetadata (type, _context);
  344. }
  345. private void WriteArray (BinaryWriter writer, long id, Array array)
  346. {
  347. // There are 4 ways of serializing arrays:
  348. // The element GenericArray (7) can be used for all arrays.
  349. // The element ArrayOfPrimitiveType (15) can be used for single-dimensional
  350. // arrays of primitive types
  351. // The element ArrayOfObject (16) can be used for single-dimensional Object arrays
  352. // The element ArrayOfString (17) can be used for single-dimensional string arrays
  353. Type elementType = array.GetType().GetElementType();
  354. if (elementType == typeof (object) && array.Rank == 1) {
  355. WriteObjectArray (writer, id, array);
  356. }
  357. else if (elementType == typeof (string) && array.Rank == 1) {
  358. WriteStringArray (writer, id, array);
  359. }
  360. else if (BinaryCommon.IsPrimitive(elementType) && array.Rank == 1) {
  361. WritePrimitiveTypeArray (writer, id, array);
  362. }
  363. else
  364. WriteGenericArray (writer, id, array);
  365. }
  366. private void WriteGenericArray (BinaryWriter writer, long id, Array array)
  367. {
  368. Type elementType = array.GetType().GetElementType();
  369. // Registers and writes the assembly of the array element type if needed
  370. if (!elementType.IsArray)
  371. WriteAssembly (writer, elementType.Assembly);
  372. // Writes the array
  373. writer.Write ((byte) BinaryElement.GenericArray);
  374. writer.Write ((int)id);
  375. // Write the structure of the array
  376. if (elementType.IsArray)
  377. writer.Write ((byte) ArrayStructure.Jagged);
  378. else if (array.Rank == 1)
  379. writer.Write ((byte) ArrayStructure.SingleDimensional);
  380. else
  381. writer.Write ((byte) ArrayStructure.MultiDimensional);
  382. // Write the number of dimensions and the length
  383. // of each dimension
  384. writer.Write (array.Rank);
  385. for (int n=0; n<array.Rank; n++)
  386. writer.Write (array.GetUpperBound (n) + 1);
  387. // Writes the type
  388. WriteTypeCode (writer, elementType);
  389. WriteTypeSpec (writer, elementType);
  390. // Writes the values. For single-dimension array, a special tag is used
  391. // to represent multiple consecutive null values. I don't know why this
  392. // optimization is not used for multidimensional arrays.
  393. if (array.Rank == 1 && !elementType.IsValueType)
  394. {
  395. WriteSingleDimensionArrayElements (writer, array, elementType);
  396. }
  397. else
  398. {
  399. foreach (object item in array)
  400. WriteValue (writer, elementType, item);
  401. }
  402. }
  403. private void WriteObjectArray (BinaryWriter writer, long id, Array array)
  404. {
  405. writer.Write ((byte) BinaryElement.ArrayOfObject);
  406. writer.Write ((int)id);
  407. writer.Write (array.Length); // Single dimension. Just write the length
  408. WriteSingleDimensionArrayElements (writer, array, typeof (object));
  409. }
  410. private void WriteStringArray (BinaryWriter writer, long id, Array array)
  411. {
  412. writer.Write ((byte) BinaryElement.ArrayOfString);
  413. writer.Write ((int)id);
  414. writer.Write (array.Length); // Single dimension. Just write the length
  415. WriteSingleDimensionArrayElements (writer, array, typeof (string));
  416. }
  417. private void WritePrimitiveTypeArray (BinaryWriter writer, long id, Array array)
  418. {
  419. writer.Write ((byte) BinaryElement.ArrayOfPrimitiveType);
  420. writer.Write ((int)id);
  421. writer.Write (array.Length); // Single dimension. Just write the length
  422. Type elementType = array.GetType().GetElementType();
  423. WriteTypeSpec (writer, elementType);
  424. switch (Type.GetTypeCode (elementType))
  425. {
  426. case TypeCode.Boolean:
  427. foreach (bool item in (bool[]) array)
  428. writer.Write (item);
  429. break;
  430. case TypeCode.Byte:
  431. writer.Write ((byte[]) array);
  432. break;
  433. case TypeCode.Char:
  434. foreach (char item in (char[]) array)
  435. writer.Write (item);
  436. break;
  437. case TypeCode.DateTime:
  438. foreach (DateTime item in (DateTime[]) array)
  439. writer.Write (item.Ticks);
  440. break;
  441. case TypeCode.Decimal:
  442. foreach (decimal item in (decimal[]) array)
  443. writer.Write (item);
  444. break;
  445. case TypeCode.Double:
  446. foreach (double item in (double[]) array)
  447. writer.Write (item);
  448. break;
  449. case TypeCode.Int16:
  450. foreach (short item in (short[]) array)
  451. writer.Write (item);
  452. break;
  453. case TypeCode.Int32:
  454. foreach (int item in (int[]) array)
  455. writer.Write (item);
  456. break;
  457. case TypeCode.Int64:
  458. foreach (long item in (long[]) array)
  459. writer.Write (item);
  460. break;
  461. case TypeCode.SByte:
  462. foreach (sbyte item in (sbyte[]) array)
  463. writer.Write (item);
  464. break;
  465. case TypeCode.Single:
  466. foreach (float item in (float[]) array)
  467. writer.Write (item);
  468. break;
  469. case TypeCode.UInt16:
  470. foreach (ushort item in (ushort[]) array)
  471. writer.Write (item);
  472. break;
  473. case TypeCode.UInt32:
  474. foreach (uint item in (uint[]) array)
  475. writer.Write (item);
  476. break;
  477. case TypeCode.UInt64:
  478. foreach (ulong item in (ulong[]) array)
  479. writer.Write (item);
  480. break;
  481. case TypeCode.String:
  482. foreach (string item in (string[]) array)
  483. writer.Write (item);
  484. break;
  485. default:
  486. if (elementType == typeof (TimeSpan)) {
  487. foreach (TimeSpan item in (TimeSpan[]) array)
  488. writer.Write (item.Ticks);
  489. }
  490. else
  491. throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
  492. break;
  493. }
  494. }
  495. private void WriteSingleDimensionArrayElements (BinaryWriter writer, Array array, Type elementType)
  496. {
  497. int numNulls = 0;
  498. foreach (object val in array)
  499. {
  500. if (val != null && numNulls > 0)
  501. {
  502. WriteNullFiller (writer, numNulls);
  503. WriteValue (writer, elementType, val);
  504. numNulls = 0;
  505. }
  506. else if (val == null)
  507. numNulls++;
  508. else
  509. WriteValue (writer, elementType, val);
  510. }
  511. if (numNulls > 0)
  512. WriteNullFiller (writer, numNulls);
  513. }
  514. private void WriteNullFiller (BinaryWriter writer, int numNulls)
  515. {
  516. if (numNulls == 1) {
  517. writer.Write ((byte) BinaryElement.NullValue);
  518. }
  519. else if (numNulls == 2) {
  520. writer.Write ((byte) BinaryElement.NullValue);
  521. writer.Write ((byte) BinaryElement.NullValue);
  522. }
  523. else if (numNulls <= byte.MaxValue) {
  524. writer.Write ((byte) BinaryElement.ArrayFiller8b);
  525. writer.Write ((byte) numNulls);
  526. }
  527. else {
  528. writer.Write ((byte) BinaryElement.ArrayFiller32b);
  529. writer.Write (numNulls);
  530. }
  531. }
  532. private void WriteObjectReference (BinaryWriter writer, long id)
  533. {
  534. writer.Write ((byte) BinaryElement.ObjectReference);
  535. writer.Write ((int)id);
  536. }
  537. public void WriteValue (BinaryWriter writer, Type valueType, object val)
  538. {
  539. if (val == null)
  540. {
  541. BinaryCommon.CheckSerializable (valueType, _surrogateSelector, _context);
  542. writer.Write ((byte) BinaryElement.NullValue);
  543. }
  544. else if (BinaryCommon.IsPrimitive(val.GetType()))
  545. {
  546. if (!BinaryCommon.IsPrimitive(valueType))
  547. {
  548. // It is a boxed primitive type value
  549. writer.Write ((byte) BinaryElement.BoxedPrimitiveTypeValue);
  550. WriteTypeSpec (writer, val.GetType());
  551. }
  552. WritePrimitiveValue (writer, val);
  553. }
  554. else if (valueType.IsValueType)
  555. {
  556. // Value types are written embedded in the containing object
  557. WriteObjectInstance (writer, val, true);
  558. }
  559. else if (val is string)
  560. {
  561. // Strings are written embedded, unless already registered
  562. bool firstTime;
  563. long id = _idGenerator.GetId (val, out firstTime);
  564. if (firstTime) WriteObjectInstance (writer, val, false);
  565. else WriteObjectReference (writer, id);
  566. }
  567. else
  568. {
  569. // It is a reference type. Write a forward reference and queue the
  570. // object to the pending object list (unless already written).
  571. bool firstTime;
  572. long id = _idGenerator.GetId (val, out firstTime);
  573. if (firstTime) _pendingObjects.Enqueue (val);
  574. WriteObjectReference (writer, id);
  575. }
  576. }
  577. private void WriteString (BinaryWriter writer, long id, string str)
  578. {
  579. writer.Write ((byte) BinaryElement.String);
  580. writer.Write ((int)id);
  581. writer.Write (str);
  582. }
  583. public int WriteAssembly (BinaryWriter writer, Assembly assembly)
  584. {
  585. if (assembly == ObjectWriter.CorlibAssembly) return -1;
  586. bool firstTime;
  587. int id = RegisterAssembly (assembly, out firstTime);
  588. if (!firstTime) return id;
  589. writer.Write ((byte) BinaryElement.Assembly);
  590. writer.Write (id);
  591. if (_assemblyFormat == FormatterAssemblyStyle.Full)
  592. writer.Write (assembly.GetName ().FullName);
  593. else
  594. writer.Write (assembly.GetName ().Name);
  595. return id;
  596. }
  597. public int GetAssemblyId (Assembly assembly)
  598. {
  599. return (int)_assemblyCache[assembly];
  600. }
  601. private int RegisterAssembly (Assembly assembly, out bool firstTime)
  602. {
  603. if (_assemblyCache.ContainsKey (assembly))
  604. {
  605. firstTime = false;
  606. return (int)_assemblyCache[assembly];
  607. }
  608. else
  609. {
  610. int id = (int)_idGenerator.GetId (0, out firstTime);
  611. _assemblyCache.Add (assembly, id);
  612. return id;
  613. }
  614. }
  615. public static void WritePrimitiveValue (BinaryWriter writer, object value)
  616. {
  617. Type type = value.GetType();
  618. switch (Type.GetTypeCode (type))
  619. {
  620. case TypeCode.Boolean:
  621. writer.Write ((bool)value);
  622. break;
  623. case TypeCode.Byte:
  624. writer.Write ((byte) value);
  625. break;
  626. case TypeCode.Char:
  627. writer.Write ((char) value);
  628. break;
  629. case TypeCode.DateTime:
  630. writer.Write ( ((DateTime)value).Ticks);
  631. break;
  632. case TypeCode.Decimal:
  633. writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture));
  634. break;
  635. case TypeCode.Double:
  636. writer.Write ((double) value);
  637. break;
  638. case TypeCode.Int16:
  639. writer.Write ((short) value);
  640. break;
  641. case TypeCode.Int32:
  642. writer.Write ((int) value);
  643. break;
  644. case TypeCode.Int64:
  645. writer.Write ((long) value);
  646. break;
  647. case TypeCode.SByte:
  648. writer.Write ((sbyte) value);
  649. break;
  650. case TypeCode.Single:
  651. writer.Write ((float) value);
  652. break;
  653. case TypeCode.UInt16:
  654. writer.Write ((ushort) value);
  655. break;
  656. case TypeCode.UInt32:
  657. writer.Write ((uint) value);
  658. break;
  659. case TypeCode.UInt64:
  660. writer.Write ((ulong) value);
  661. break;
  662. case TypeCode.String:
  663. writer.Write ((string) value);
  664. break;
  665. default:
  666. if (type == typeof (TimeSpan))
  667. writer.Write (((TimeSpan)value).Ticks);
  668. else
  669. throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName);
  670. break;
  671. }
  672. }
  673. public static void WriteTypeCode (BinaryWriter writer, Type type)
  674. {
  675. writer.Write ((byte) GetTypeTag (type));
  676. }
  677. public static TypeTag GetTypeTag (Type type)
  678. {
  679. if (type == typeof (string)) {
  680. return TypeTag.String;
  681. }
  682. else if (BinaryCommon.IsPrimitive (type)) {
  683. return TypeTag.PrimitiveType;
  684. }
  685. else if (type == typeof (object)) {
  686. return TypeTag.ObjectType;
  687. }
  688. else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (object)) {
  689. return TypeTag.ArrayOfObject;
  690. }
  691. else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (string)){
  692. return TypeTag.ArrayOfString;
  693. }
  694. else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) {
  695. return TypeTag.ArrayOfPrimitiveType;
  696. }
  697. else if (type.Assembly == CorlibAssembly) {
  698. return TypeTag.RuntimeType;
  699. }
  700. else
  701. return TypeTag.GenericType;
  702. }
  703. public void WriteTypeSpec (BinaryWriter writer, Type type)
  704. {
  705. // WARNING Keep in sync with EmitWriteTypeSpec
  706. switch (GetTypeTag (type))
  707. {
  708. case TypeTag.PrimitiveType:
  709. writer.Write (BinaryCommon.GetTypeCode (type));
  710. break;
  711. case TypeTag.RuntimeType:
  712. writer.Write (type.FullName);
  713. break;
  714. case TypeTag.GenericType:
  715. writer.Write (type.FullName);
  716. writer.Write ((int)GetAssemblyId (type.Assembly));
  717. break;
  718. case TypeTag.ArrayOfPrimitiveType:
  719. writer.Write (BinaryCommon.GetTypeCode (type.GetElementType()));
  720. break;
  721. default:
  722. // Type spec not needed
  723. break;
  724. }
  725. }
  726. }
  727. }