ObjectWriter.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  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 string TypeAssemblyName;
  41. public string InstanceTypeName;
  42. public abstract void WriteAssemblies (ObjectWriter ow, BinaryWriter writer);
  43. public abstract void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes);
  44. public abstract void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data);
  45. public virtual bool IsCompatible (TypeMetadata other)
  46. {
  47. return true;
  48. }
  49. public abstract bool RequiresTypes { get; }
  50. }
  51. abstract class ClrTypeMetadata: TypeMetadata
  52. {
  53. public Type InstanceType;
  54. public ClrTypeMetadata (Type instanceType)
  55. {
  56. InstanceType = instanceType;
  57. InstanceTypeName = instanceType.FullName;
  58. TypeAssemblyName = instanceType.Assembly.FullName;
  59. }
  60. public override bool RequiresTypes {
  61. get { return false; }
  62. }
  63. }
  64. class SerializableTypeMetadata: TypeMetadata
  65. {
  66. Type[] types;
  67. string[] names;
  68. public SerializableTypeMetadata (Type itype, SerializationInfo info)
  69. {
  70. types = new Type [info.MemberCount];
  71. names = new string [info.MemberCount];
  72. SerializationInfoEnumerator e = info.GetEnumerator ();
  73. int n = 0;
  74. while (e.MoveNext ())
  75. {
  76. types[n] = e.ObjectType;
  77. names[n] = e.Name;
  78. n++;
  79. }
  80. TypeAssemblyName = info.AssemblyName;
  81. InstanceTypeName = info.FullTypeName;
  82. }
  83. public override bool IsCompatible (TypeMetadata other)
  84. {
  85. if (!(other is SerializableTypeMetadata)) return false;
  86. SerializableTypeMetadata tm = (SerializableTypeMetadata)other;
  87. if (types.Length != tm.types.Length) return false;
  88. if (TypeAssemblyName != tm.TypeAssemblyName) return false;
  89. if (InstanceTypeName != tm.InstanceTypeName) return false;
  90. for (int n=0; n<types.Length; n++)
  91. {
  92. if (types[n] != tm.types[n]) return false;
  93. if (names[n] != tm.names[n]) return false;
  94. }
  95. return true;
  96. }
  97. public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
  98. {
  99. foreach (Type mtype in types)
  100. {
  101. Type type = mtype;
  102. while (type.IsArray)
  103. type = type.GetElementType();
  104. ow.WriteAssembly (writer, type.Assembly);
  105. }
  106. }
  107. public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)
  108. {
  109. writer.Write (types.Length);
  110. // Names of fields
  111. foreach (string name in names)
  112. writer.Write (name);
  113. // Types of fields
  114. foreach (Type type in types)
  115. ObjectWriter.WriteTypeCode (writer, type);
  116. // Type specs of fields
  117. foreach (Type type in types)
  118. ow.WriteTypeSpec (writer, type);
  119. }
  120. public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
  121. {
  122. SerializationInfo info = (SerializationInfo) data;
  123. SerializationInfoEnumerator e = info.GetEnumerator ();
  124. while (e.MoveNext ())
  125. ow.WriteValue (writer, e.ObjectType, e.Value);
  126. }
  127. public override bool RequiresTypes {
  128. get { return true; }
  129. }
  130. }
  131. class MemberTypeMetadata: ClrTypeMetadata
  132. {
  133. MemberInfo[] members;
  134. public MemberTypeMetadata (Type type, StreamingContext context): base (type)
  135. {
  136. members = FormatterServices.GetSerializableMembers (type, context);
  137. }
  138. public override void WriteAssemblies (ObjectWriter ow, BinaryWriter writer)
  139. {
  140. foreach (FieldInfo field in members)
  141. {
  142. Type type = field.FieldType;
  143. while (type.IsArray)
  144. type = type.GetElementType();
  145. ow.WriteAssembly (writer, type.Assembly);
  146. }
  147. }
  148. public override void WriteTypeData (ObjectWriter ow, BinaryWriter writer, bool writeTypes)
  149. {
  150. writer.Write (members.Length);
  151. // Names of fields
  152. foreach (FieldInfo field in members)
  153. writer.Write (field.Name);
  154. if (writeTypes) {
  155. // Types of fields
  156. foreach (FieldInfo field in members)
  157. ObjectWriter.WriteTypeCode (writer, field.FieldType);
  158. // Type specs of fields
  159. foreach (FieldInfo field in members)
  160. ow.WriteTypeSpec (writer, field.FieldType);
  161. }
  162. }
  163. public override void WriteObjectData (ObjectWriter ow, BinaryWriter writer, object data)
  164. {
  165. object[] values = FormatterServices.GetObjectData (data, members);
  166. for (int n=0; n<values.Length; n++)
  167. ow.WriteValue (writer, ((FieldInfo)members[n]).FieldType, values[n]);
  168. }
  169. }
  170. internal class ObjectWriter
  171. {
  172. ObjectIDGenerator _idGenerator = new ObjectIDGenerator();
  173. Hashtable _cachedMetadata = new Hashtable();
  174. Queue _pendingObjects = new Queue();
  175. Hashtable _assemblyCache = new Hashtable();
  176. // Type metadata that can be shared with all serializers
  177. static Hashtable _cachedTypes = new Hashtable();
  178. internal static Assembly CorlibAssembly = typeof(string).Assembly;
  179. internal static string CorlibAssemblyName = typeof(string).Assembly.FullName;
  180. ISurrogateSelector _surrogateSelector;
  181. StreamingContext _context;
  182. FormatterAssemblyStyle _assemblyFormat;
  183. FormatterTypeStyle _typeFormat;
  184. byte[] arrayBuffer;
  185. int ArrayBufferLength = 4096;
  186. #if NET_2_0
  187. SerializationObjectManager _manager;
  188. #endif
  189. class MetadataReference
  190. {
  191. public TypeMetadata Metadata;
  192. public long ObjectID;
  193. public MetadataReference (TypeMetadata metadata, long id)
  194. {
  195. Metadata = metadata;
  196. ObjectID = id;
  197. }
  198. }
  199. public ObjectWriter (ISurrogateSelector surrogateSelector, StreamingContext context, FormatterAssemblyStyle assemblyFormat, FormatterTypeStyle typeFormat)
  200. {
  201. _surrogateSelector = surrogateSelector;
  202. _context = context;
  203. _assemblyFormat = assemblyFormat;
  204. _typeFormat = typeFormat;
  205. #if NET_2_0
  206. _manager = new SerializationObjectManager (context);
  207. #endif
  208. }
  209. public void WriteObjectGraph (BinaryWriter writer, object obj, Header[] headers)
  210. {
  211. _pendingObjects.Clear();
  212. if (headers != null) QueueObject (headers);
  213. QueueObject (obj);
  214. WriteQueuedObjects (writer);
  215. WriteSerializationEnd (writer);
  216. #if NET_2_0
  217. _manager.RaiseOnSerializedEvent ();
  218. #endif
  219. }
  220. public void QueueObject (object obj)
  221. {
  222. _pendingObjects.Enqueue (obj);
  223. }
  224. public void WriteQueuedObjects (BinaryWriter writer)
  225. {
  226. while (_pendingObjects.Count > 0)
  227. WriteObjectInstance (writer, _pendingObjects.Dequeue(), false);
  228. }
  229. public void WriteObjectInstance (BinaryWriter writer, object obj, bool isValueObject)
  230. {
  231. bool firstTime;
  232. long id;
  233. // If the object is a value type (not boxed) then there is no need
  234. // to register it in the id generator, because it won't have other
  235. // references to it
  236. if (isValueObject) id = _idGenerator.NextId;
  237. else id = _idGenerator.GetId (obj, out firstTime);
  238. if (obj is string) {
  239. WriteString (writer, id, (string)obj);
  240. }
  241. else if (obj is Array) {
  242. WriteArray (writer, id, (Array)obj);
  243. }
  244. else
  245. WriteObject (writer, id, obj);
  246. }
  247. public static void WriteSerializationEnd (BinaryWriter writer)
  248. {
  249. writer.Write ((byte) BinaryElement.End);
  250. }
  251. private void WriteObject (BinaryWriter writer, long id, object obj)
  252. {
  253. object data;
  254. TypeMetadata metadata;
  255. GetObjectData (obj, out metadata, out data);
  256. MetadataReference metadataReference = (MetadataReference)_cachedMetadata [metadata.InstanceTypeName];
  257. if (metadataReference != null && metadata.IsCompatible (metadataReference.Metadata))
  258. {
  259. // An object of the same type has already been serialized
  260. // It is not necessary to write again type metadata
  261. writer.Write ((byte) BinaryElement.RefTypeObject);
  262. writer.Write ((int)id);
  263. writer.Write ((int)metadataReference.ObjectID);
  264. metadata.WriteObjectData (this, writer, data);
  265. return;
  266. }
  267. if (metadataReference == null)
  268. {
  269. metadataReference = new MetadataReference (metadata, id);
  270. _cachedMetadata [metadata.InstanceTypeName] = metadataReference;
  271. }
  272. bool writeTypes = metadata.RequiresTypes || _typeFormat == FormatterTypeStyle.TypesAlways;
  273. BinaryElement objectTag;
  274. int assemblyId;
  275. if (metadata.TypeAssemblyName == CorlibAssemblyName)
  276. {
  277. // A corlib type
  278. objectTag = writeTypes ? BinaryElement.RuntimeObject : BinaryElement.UntypedRuntimeObject;
  279. assemblyId = -1;
  280. }
  281. else
  282. {
  283. objectTag = writeTypes ? BinaryElement.ExternalObject : BinaryElement.UntypedExternalObject;
  284. assemblyId = WriteAssemblyName (writer, metadata.TypeAssemblyName);
  285. }
  286. // Registers the assemblies needed for each field
  287. // If there are assemblies that where not registered before this object,
  288. // write them now
  289. metadata.WriteAssemblies (this, writer);
  290. // Writes the object
  291. writer.Write ((byte) objectTag);
  292. writer.Write ((int)id);
  293. writer.Write (metadata.InstanceTypeName);
  294. metadata.WriteTypeData (this, writer, writeTypes);
  295. if (assemblyId != -1) writer.Write (assemblyId);
  296. metadata.WriteObjectData (this, writer, data);
  297. }
  298. private void GetObjectData (object obj, out TypeMetadata metadata, out object data)
  299. {
  300. Type instanceType = obj.GetType();
  301. // Check if the formatter has a surrogate selector, if it does,
  302. // check if the surrogate selector handles objects of the given type.
  303. if (_surrogateSelector != null)
  304. {
  305. ISurrogateSelector selector;
  306. ISerializationSurrogate surrogate = _surrogateSelector.GetSurrogate (instanceType, _context, out selector);
  307. if (surrogate != null)
  308. {
  309. SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
  310. surrogate.GetObjectData (obj, info, _context);
  311. metadata = new SerializableTypeMetadata (instanceType, info);
  312. data = info;
  313. return;
  314. }
  315. }
  316. // Check if the object is marked with the Serializable attribute
  317. BinaryCommon.CheckSerializable (instanceType, _surrogateSelector, _context);
  318. #if NET_2_0
  319. _manager.RegisterObject (obj);
  320. #endif
  321. ISerializable ser = obj as ISerializable;
  322. if (ser != null)
  323. {
  324. SerializationInfo info = new SerializationInfo (instanceType, new FormatterConverter ());
  325. ser.GetObjectData (info, _context);
  326. metadata = new SerializableTypeMetadata (instanceType, info);
  327. data = info;
  328. }
  329. else
  330. {
  331. data = obj;
  332. if (_context.Context != null)
  333. {
  334. // Don't cache metadata info when the Context property is not null sice
  335. // we can't control the number of possible contexts in this case
  336. metadata = new MemberTypeMetadata (instanceType, _context);
  337. return;
  338. }
  339. Hashtable typesTable;
  340. bool isNew = false;
  341. lock (_cachedTypes) {
  342. typesTable = (Hashtable) _cachedTypes [_context.State];
  343. if (typesTable == null) {
  344. typesTable = new Hashtable ();
  345. _cachedTypes [_context.State] = typesTable;
  346. isNew = true;
  347. }
  348. }
  349. metadata = null;
  350. lock (typesTable) {
  351. if (!isNew) {
  352. metadata = (TypeMetadata) typesTable [instanceType];
  353. }
  354. if (metadata == null) {
  355. metadata = CreateMemberTypeMetadata (instanceType);
  356. }
  357. typesTable [instanceType] = metadata;
  358. }
  359. }
  360. }
  361. TypeMetadata CreateMemberTypeMetadata (Type type)
  362. {
  363. if (!BinaryCommon.UseReflectionSerialization) {
  364. Type metaType = CodeGenerator.GenerateMetadataType (type, _context);
  365. return (TypeMetadata) Activator.CreateInstance (metaType);
  366. }
  367. else
  368. return new MemberTypeMetadata (type, _context);
  369. }
  370. private void WriteArray (BinaryWriter writer, long id, Array array)
  371. {
  372. // There are 4 ways of serializing arrays:
  373. // The element GenericArray (7) can be used for all arrays.
  374. // The element ArrayOfPrimitiveType (15) can be used for single-dimensional
  375. // arrays of primitive types
  376. // The element ArrayOfObject (16) can be used for single-dimensional Object arrays
  377. // The element ArrayOfString (17) can be used for single-dimensional string arrays
  378. Type elementType = array.GetType().GetElementType();
  379. if (elementType == typeof (object) && array.Rank == 1) {
  380. WriteObjectArray (writer, id, array);
  381. }
  382. else if (elementType == typeof (string) && array.Rank == 1) {
  383. WriteStringArray (writer, id, array);
  384. }
  385. else if (BinaryCommon.IsPrimitive(elementType) && array.Rank == 1) {
  386. WritePrimitiveTypeArray (writer, id, array);
  387. }
  388. else
  389. WriteGenericArray (writer, id, array);
  390. }
  391. private void WriteGenericArray (BinaryWriter writer, long id, Array array)
  392. {
  393. Type elementType = array.GetType().GetElementType();
  394. // Registers and writes the assembly of the array element type if needed
  395. if (!elementType.IsArray)
  396. WriteAssembly (writer, elementType.Assembly);
  397. // Writes the array
  398. writer.Write ((byte) BinaryElement.GenericArray);
  399. writer.Write ((int)id);
  400. // Write the structure of the array
  401. if (elementType.IsArray)
  402. writer.Write ((byte) ArrayStructure.Jagged);
  403. else if (array.Rank == 1)
  404. writer.Write ((byte) ArrayStructure.SingleDimensional);
  405. else
  406. writer.Write ((byte) ArrayStructure.MultiDimensional);
  407. // Write the number of dimensions and the length
  408. // of each dimension
  409. writer.Write (array.Rank);
  410. for (int n=0; n<array.Rank; n++)
  411. writer.Write (array.GetUpperBound (n) + 1);
  412. // Writes the type
  413. WriteTypeCode (writer, elementType);
  414. WriteTypeSpec (writer, elementType);
  415. // Writes the values. For single-dimension array, a special tag is used
  416. // to represent multiple consecutive null values. I don't know why this
  417. // optimization is not used for multidimensional arrays.
  418. if (array.Rank == 1 && !elementType.IsValueType)
  419. {
  420. WriteSingleDimensionArrayElements (writer, array, elementType);
  421. }
  422. else
  423. {
  424. foreach (object item in array)
  425. WriteValue (writer, elementType, item);
  426. }
  427. }
  428. private void WriteObjectArray (BinaryWriter writer, long id, Array array)
  429. {
  430. writer.Write ((byte) BinaryElement.ArrayOfObject);
  431. writer.Write ((int)id);
  432. writer.Write (array.Length); // Single dimension. Just write the length
  433. WriteSingleDimensionArrayElements (writer, array, typeof (object));
  434. }
  435. private void WriteStringArray (BinaryWriter writer, long id, Array array)
  436. {
  437. writer.Write ((byte) BinaryElement.ArrayOfString);
  438. writer.Write ((int)id);
  439. writer.Write (array.Length); // Single dimension. Just write the length
  440. WriteSingleDimensionArrayElements (writer, array, typeof (string));
  441. }
  442. private void WritePrimitiveTypeArray (BinaryWriter writer, long id, Array array)
  443. {
  444. writer.Write ((byte) BinaryElement.ArrayOfPrimitiveType);
  445. writer.Write ((int)id);
  446. writer.Write (array.Length); // Single dimension. Just write the length
  447. Type elementType = array.GetType().GetElementType();
  448. WriteTypeSpec (writer, elementType);
  449. switch (Type.GetTypeCode (elementType))
  450. {
  451. case TypeCode.Boolean:
  452. foreach (bool item in (bool[]) array)
  453. writer.Write (item);
  454. break;
  455. case TypeCode.Byte:
  456. writer.Write ((byte[]) array);
  457. break;
  458. case TypeCode.Char:
  459. writer.Write ((char[]) array);
  460. break;
  461. case TypeCode.DateTime:
  462. foreach (DateTime item in (DateTime[]) array) {
  463. ulong val = (ulong) item.Ticks;
  464. #if NET_2_0
  465. val |= ((ulong) item.Kind) << 62;
  466. #endif
  467. writer.Write (val);
  468. }
  469. break;
  470. case TypeCode.Decimal:
  471. foreach (decimal item in (decimal[]) array)
  472. writer.Write (item);
  473. break;
  474. case TypeCode.Double:
  475. if (array.Length > 2)
  476. BlockWrite (writer, array, 8);
  477. else
  478. foreach (double item in (double[]) array)
  479. writer.Write (item);
  480. break;
  481. case TypeCode.Int16:
  482. if (array.Length > 2)
  483. BlockWrite (writer, array, 2);
  484. else
  485. foreach (short item in (short[]) array)
  486. writer.Write (item);
  487. break;
  488. case TypeCode.Int32:
  489. if (array.Length > 2)
  490. BlockWrite (writer, array, 4);
  491. else
  492. foreach (int item in (int[]) array)
  493. writer.Write (item);
  494. break;
  495. case TypeCode.Int64:
  496. if (array.Length > 2)
  497. BlockWrite (writer, array, 8);
  498. else
  499. foreach (long item in (long[]) array)
  500. writer.Write (item);
  501. break;
  502. case TypeCode.SByte:
  503. if (array.Length > 2)
  504. BlockWrite (writer, array, 1);
  505. else
  506. foreach (sbyte item in (sbyte[]) array)
  507. writer.Write (item);
  508. break;
  509. case TypeCode.Single:
  510. if (array.Length > 2)
  511. BlockWrite (writer, array, 4);
  512. else
  513. foreach (float item in (float[]) array)
  514. writer.Write (item);
  515. break;
  516. case TypeCode.UInt16:
  517. if (array.Length > 2)
  518. BlockWrite (writer, array, 2);
  519. else
  520. foreach (ushort item in (ushort[]) array)
  521. writer.Write (item);
  522. break;
  523. case TypeCode.UInt32:
  524. if (array.Length > 2)
  525. BlockWrite (writer, array, 4);
  526. else
  527. foreach (uint item in (uint[]) array)
  528. writer.Write (item);
  529. break;
  530. case TypeCode.UInt64:
  531. if (array.Length > 2)
  532. BlockWrite (writer, array, 8);
  533. else
  534. foreach (ulong item in (ulong[]) array)
  535. writer.Write (item);
  536. break;
  537. case TypeCode.String:
  538. foreach (string item in (string[]) array)
  539. writer.Write (item);
  540. break;
  541. default:
  542. if (elementType == typeof (TimeSpan)) {
  543. foreach (TimeSpan item in (TimeSpan[]) array)
  544. writer.Write (item.Ticks);
  545. }
  546. else
  547. throw new NotSupportedException ("Unsupported primitive type: " + elementType.FullName);
  548. break;
  549. }
  550. }
  551. private void BlockWrite (BinaryWriter writer, Array array, int dataSize)
  552. {
  553. int totalSize = Buffer.ByteLength (array);
  554. if (arrayBuffer == null || (totalSize > arrayBuffer.Length && arrayBuffer.Length != ArrayBufferLength))
  555. arrayBuffer = new byte [totalSize <= ArrayBufferLength ? totalSize : ArrayBufferLength];
  556. int pos = 0;
  557. while (totalSize > 0) {
  558. int size = totalSize < arrayBuffer.Length ? totalSize : arrayBuffer.Length;
  559. Buffer.BlockCopy (array, pos, arrayBuffer, 0, size);
  560. if (!BitConverter.IsLittleEndian && dataSize > 1)
  561. BinaryCommon.SwapBytes (arrayBuffer, size, dataSize);
  562. writer.Write (arrayBuffer, 0, size);
  563. totalSize -= size;
  564. pos += size;
  565. }
  566. }
  567. private void WriteSingleDimensionArrayElements (BinaryWriter writer, Array array, Type elementType)
  568. {
  569. int numNulls = 0;
  570. foreach (object val in array)
  571. {
  572. if (val != null && numNulls > 0)
  573. {
  574. WriteNullFiller (writer, numNulls);
  575. WriteValue (writer, elementType, val);
  576. numNulls = 0;
  577. }
  578. else if (val == null)
  579. numNulls++;
  580. else
  581. WriteValue (writer, elementType, val);
  582. }
  583. if (numNulls > 0)
  584. WriteNullFiller (writer, numNulls);
  585. }
  586. private void WriteNullFiller (BinaryWriter writer, int numNulls)
  587. {
  588. if (numNulls == 1) {
  589. writer.Write ((byte) BinaryElement.NullValue);
  590. }
  591. else if (numNulls == 2) {
  592. writer.Write ((byte) BinaryElement.NullValue);
  593. writer.Write ((byte) BinaryElement.NullValue);
  594. }
  595. else if (numNulls <= byte.MaxValue) {
  596. writer.Write ((byte) BinaryElement.ArrayFiller8b);
  597. writer.Write ((byte) numNulls);
  598. }
  599. else {
  600. writer.Write ((byte) BinaryElement.ArrayFiller32b);
  601. writer.Write (numNulls);
  602. }
  603. }
  604. private void WriteObjectReference (BinaryWriter writer, long id)
  605. {
  606. writer.Write ((byte) BinaryElement.ObjectReference);
  607. writer.Write ((int)id);
  608. }
  609. public void WriteValue (BinaryWriter writer, Type valueType, object val)
  610. {
  611. if (val == null)
  612. {
  613. BinaryCommon.CheckSerializable (valueType, _surrogateSelector, _context);
  614. writer.Write ((byte) BinaryElement.NullValue);
  615. }
  616. else if (BinaryCommon.IsPrimitive(val.GetType()))
  617. {
  618. if (!BinaryCommon.IsPrimitive(valueType))
  619. {
  620. // It is a boxed primitive type value
  621. writer.Write ((byte) BinaryElement.BoxedPrimitiveTypeValue);
  622. WriteTypeSpec (writer, val.GetType());
  623. }
  624. WritePrimitiveValue (writer, val);
  625. }
  626. else if (valueType.IsValueType)
  627. {
  628. // Value types are written embedded in the containing object
  629. WriteObjectInstance (writer, val, true);
  630. }
  631. else if (val is string)
  632. {
  633. // Strings are written embedded, unless already registered
  634. bool firstTime;
  635. long id = _idGenerator.GetId (val, out firstTime);
  636. if (firstTime) WriteObjectInstance (writer, val, false);
  637. else WriteObjectReference (writer, id);
  638. }
  639. else
  640. {
  641. // It is a reference type. Write a forward reference and queue the
  642. // object to the pending object list (unless already written).
  643. bool firstTime;
  644. long id = _idGenerator.GetId (val, out firstTime);
  645. if (firstTime) _pendingObjects.Enqueue (val);
  646. WriteObjectReference (writer, id);
  647. }
  648. }
  649. private void WriteString (BinaryWriter writer, long id, string str)
  650. {
  651. writer.Write ((byte) BinaryElement.String);
  652. writer.Write ((int)id);
  653. writer.Write (str);
  654. }
  655. public int WriteAssembly (BinaryWriter writer, Assembly assembly)
  656. {
  657. return WriteAssemblyName (writer, assembly.FullName);
  658. }
  659. public int WriteAssemblyName (BinaryWriter writer, string assembly)
  660. {
  661. if (assembly == ObjectWriter.CorlibAssemblyName) return -1;
  662. bool firstTime;
  663. int id = RegisterAssembly (assembly, out firstTime);
  664. if (!firstTime) return id;
  665. writer.Write ((byte) BinaryElement.Assembly);
  666. writer.Write (id);
  667. if (_assemblyFormat == FormatterAssemblyStyle.Full)
  668. writer.Write (assembly);
  669. else {
  670. int i = assembly.IndexOf (',');
  671. if (i != -1) assembly = assembly.Substring (0, i);
  672. writer.Write (assembly);
  673. }
  674. return id;
  675. }
  676. public int GetAssemblyId (Assembly assembly)
  677. {
  678. return GetAssemblyNameId (assembly.FullName);
  679. }
  680. public int GetAssemblyNameId (string assembly)
  681. {
  682. return (int)_assemblyCache[assembly];
  683. }
  684. private int RegisterAssembly (string assembly, out bool firstTime)
  685. {
  686. if (_assemblyCache.ContainsKey (assembly))
  687. {
  688. firstTime = false;
  689. return (int)_assemblyCache[assembly];
  690. }
  691. else
  692. {
  693. int id = (int)_idGenerator.GetId (0, out firstTime);
  694. _assemblyCache.Add (assembly, id);
  695. return id;
  696. }
  697. }
  698. public static void WritePrimitiveValue (BinaryWriter writer, object value)
  699. {
  700. Type type = value.GetType();
  701. switch (Type.GetTypeCode (type))
  702. {
  703. case TypeCode.Boolean:
  704. writer.Write ((bool)value);
  705. break;
  706. case TypeCode.Byte:
  707. writer.Write ((byte) value);
  708. break;
  709. case TypeCode.Char:
  710. writer.Write ((char) value);
  711. break;
  712. case TypeCode.DateTime:
  713. writer.Write ( ((DateTime)value).Ticks);
  714. break;
  715. case TypeCode.Decimal:
  716. writer.Write (((decimal) value).ToString (CultureInfo.InvariantCulture));
  717. break;
  718. case TypeCode.Double:
  719. writer.Write ((double) value);
  720. break;
  721. case TypeCode.Int16:
  722. writer.Write ((short) value);
  723. break;
  724. case TypeCode.Int32:
  725. writer.Write ((int) value);
  726. break;
  727. case TypeCode.Int64:
  728. writer.Write ((long) value);
  729. break;
  730. case TypeCode.SByte:
  731. writer.Write ((sbyte) value);
  732. break;
  733. case TypeCode.Single:
  734. writer.Write ((float) value);
  735. break;
  736. case TypeCode.UInt16:
  737. writer.Write ((ushort) value);
  738. break;
  739. case TypeCode.UInt32:
  740. writer.Write ((uint) value);
  741. break;
  742. case TypeCode.UInt64:
  743. writer.Write ((ulong) value);
  744. break;
  745. case TypeCode.String:
  746. writer.Write ((string) value);
  747. break;
  748. default:
  749. if (type == typeof (TimeSpan))
  750. writer.Write (((TimeSpan)value).Ticks);
  751. else
  752. throw new NotSupportedException ("Unsupported primitive type: " + value.GetType().FullName);
  753. break;
  754. }
  755. }
  756. public static void WriteTypeCode (BinaryWriter writer, Type type)
  757. {
  758. writer.Write ((byte) GetTypeTag (type));
  759. }
  760. public static TypeTag GetTypeTag (Type type)
  761. {
  762. if (type == typeof (string)) {
  763. return TypeTag.String;
  764. }
  765. else if (BinaryCommon.IsPrimitive (type)) {
  766. return TypeTag.PrimitiveType;
  767. }
  768. else if (type == typeof (object)) {
  769. return TypeTag.ObjectType;
  770. }
  771. else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (object)) {
  772. return TypeTag.ArrayOfObject;
  773. }
  774. else if (type.IsArray && type.GetArrayRank() == 1 && type.GetElementType() == typeof (string)){
  775. return TypeTag.ArrayOfString;
  776. }
  777. else if (type.IsArray && type.GetArrayRank() == 1 && BinaryCommon.IsPrimitive(type.GetElementType())) {
  778. return TypeTag.ArrayOfPrimitiveType;
  779. }
  780. else if (type.Assembly == CorlibAssembly) {
  781. return TypeTag.RuntimeType;
  782. }
  783. else
  784. return TypeTag.GenericType;
  785. }
  786. public void WriteTypeSpec (BinaryWriter writer, Type type)
  787. {
  788. // WARNING Keep in sync with EmitWriteTypeSpec
  789. switch (GetTypeTag (type))
  790. {
  791. case TypeTag.PrimitiveType:
  792. writer.Write (BinaryCommon.GetTypeCode (type));
  793. break;
  794. case TypeTag.RuntimeType:
  795. string fullName = type.FullName;
  796. #if NET_2_0
  797. // Map System.MonoType to MS.NET's System.RuntimeType,
  798. // when called in remoting context.
  799. // Note that this code does not need to be in sync with
  800. // EmitWriteTypeSpec because serializing a MethodCall
  801. // won't trigger the CodeGenerator.
  802. if (_context.State == StreamingContextStates.Remoting)
  803. if (type == typeof (System.MonoType))
  804. fullName = "System.RuntimeType";
  805. else if (type == typeof (System.MonoType[]))
  806. fullName = "System.RuntimeType[]";
  807. #endif
  808. writer.Write (fullName);
  809. break;
  810. case TypeTag.GenericType:
  811. writer.Write (type.FullName);
  812. writer.Write ((int)GetAssemblyId (type.Assembly));
  813. break;
  814. case TypeTag.ArrayOfPrimitiveType:
  815. writer.Write (BinaryCommon.GetTypeCode (type.GetElementType()));
  816. break;
  817. default:
  818. // Type spec not needed
  819. break;
  820. }
  821. }
  822. }
  823. }