PageRenderTime 57ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/Source/SharpDX/Serialization/BinarySerializer.cs

https://github.com/KarimLUCCIN/SharpDX
C# | 2838 lines | 1877 code | 358 blank | 603 comment | 271 complexity | fd263dfbb644ab642c1f1ef74ec2b5d8 MD5 | raw file
Possible License(s): Unlicense, AGPL-3.0, GPL-2.0, CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full file

  1. // Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. using System;
  21. using System.Collections.Generic;
  22. using System.IO;
  23. using System.Text;
  24. using SharpDX.IO;
  25. using SharpDX.Multimedia;
  26. using System.Reflection;
  27. namespace SharpDX.Serialization
  28. {
  29. /// <summary>
  30. /// Serializer action.
  31. /// </summary>
  32. /// <param name="value">The value to read or write.</param>
  33. /// <param name="serializer">The serializer.</param>
  34. public delegate void SerializerAction(ref object value, BinarySerializer serializer);
  35. /// <summary>
  36. /// This class provides serialization methods for types implementing the <see cref="IDataSerializable"/>.
  37. /// </summary>
  38. /// <remarks>
  39. /// BinarySerializer is a basic binary serializer with the following features:
  40. /// <ul>
  41. /// <li>10x times faster and smaller than default System Serialization and Xml Serialization.</li>
  42. /// <li>Supports for all primitive types, array/List&lt;T&gt;/Dictionary of primitive types, custom data via <see cref="IDataSerializable"/> (struct or class) and array/List/Dictionary of custom data.</li>
  43. /// <li>Optimized binary format, data serialized to the strict minimum.</li>
  44. /// <li>Should be compatible with Win8/WinRT, Desktop.</li>
  45. /// <li>Not reflection based serializer, but fully compile time serializer.</li>
  46. /// <li>Format could be read back from C/C++.</li>
  47. ///
  48. /// </ul>
  49. /// </remarks>
  50. public class BinarySerializer : Component
  51. {
  52. private int chunkCount;
  53. private Chunk[] chunks;
  54. private Chunk currentChunk;
  55. private readonly Dictionary<FourCC, Dynamic> dynamicMapToType;
  56. private readonly Dictionary<Type, Dynamic> dynamicMapToFourCC;
  57. private readonly Dictionary<object, int> objectToPosition;
  58. private readonly Dictionary<int, object> positionToObject;
  59. private Dictionary<object, object> mapTag;
  60. private int allowIdentityReferenceCount;
  61. // Fields used to serialize strings
  62. private System.Text.Encoding encoding;
  63. private System.Text.Encoder encoder;
  64. private System.Text.Decoder decoder;
  65. private const int LargeByteBufferSize = 1024;
  66. private byte[] largeByteBuffer;
  67. private int maxChars; // max # of chars we can put in _largeByteBuffer
  68. private char[] largeCharBuffer;
  69. private int maxCharSize; // From LargeByteBufferSize & Encoding
  70. public delegate void SerializerPrimitiveAction<T>(ref T value);
  71. public delegate void SerializerTypeAction<T>(ref T value, BinarySerializer serializer);
  72. public delegate object ReadRef(BinarySerializer serializer);
  73. public delegate void WriteRef(object value, BinarySerializer serializer);
  74. /// <summary>
  75. /// Underlying stream this instance is reading/writing to.
  76. /// </summary>
  77. public Stream Stream { get; private set; }
  78. /// <summary>
  79. /// Reader used to directly read from the underlying stream.
  80. /// </summary>
  81. public BinaryReader Reader { get; private set; }
  82. /// <summary>
  83. /// Gets the reader and throws an exception if this serializer is in Write mode.
  84. /// </summary>
  85. /// <param name="context">The context object that requires a Reader.</param>
  86. /// <returns>A BinaryReader.</returns>
  87. /// <exception cref="System.ArgumentNullException">context</exception>
  88. /// <exception cref="System.InvalidOperationException">If this reader is not in read mode</exception>
  89. public BinaryReader ReaderOnly(object context)
  90. {
  91. if (context == null)
  92. {
  93. throw new ArgumentNullException("context");
  94. }
  95. if (Mode != SerializerMode.Read)
  96. {
  97. throw new InvalidOperationException(string.Format("[{0}] is only expecting Read-Only BinarySerializer", context.GetType().Name));
  98. }
  99. return Reader;
  100. }
  101. /// <summary>
  102. /// Writer used to directly write to the underlying stream.
  103. /// </summary>
  104. public BinaryWriter Writer { get; private set; }
  105. public ArrayLengthType ArrayLengthType { get; set; }
  106. private SerializerMode mode;
  107. /// <summary>
  108. /// Initializes a new instance of the <see cref="BinarySerializer" /> class.
  109. /// </summary>
  110. /// <param name="stream">The stream to read or write to.</param>
  111. /// <param name="mode">The read or write mode.</param>
  112. public BinarySerializer(Stream stream, SerializerMode mode) : this(stream, mode, SharpDX.Text.Encoding.ASCII)
  113. {
  114. }
  115. /// <summary>
  116. /// Initializes a new instance of the <see cref="BinarySerializer" /> class.
  117. /// </summary>
  118. /// <param name="stream">The stream to read or write to.</param>
  119. /// <param name="mode">The read or write mode.</param>
  120. /// <param name="encoding">Default encoding used for strings. This parameter can be overriden later using Encoding property.</param>
  121. public BinarySerializer(Stream stream, SerializerMode mode, System.Text.Encoding encoding)
  122. {
  123. // Setup the encoding used for strings.
  124. Encoding = encoding;
  125. // Allocate dictionary used for dynamic serialization.
  126. dynamicMapToType = new Dictionary<FourCC, Dynamic>();
  127. dynamicMapToFourCC = new Dictionary<Type, Dynamic>();
  128. // For serializing reference
  129. objectToPosition = new Dictionary<object, int>(new IdentityEqualityComparer<object>());
  130. positionToObject = new Dictionary<int, object>();
  131. // Allocate the chunk array and initial chunk.
  132. chunks = new Chunk[8];
  133. Stream = stream;
  134. // Setup the mode.
  135. Mode = mode;
  136. CurrentChunk = new Chunk { ChunkIndexStart = 0 };
  137. chunks[chunkCount] = CurrentChunk;
  138. chunkCount++;
  139. // Register all default dynamics.
  140. foreach (var defaultDynamic in DefaultDynamics)
  141. RegisterDynamic(defaultDynamic);
  142. RegisterDynamic<Color4>();
  143. RegisterDynamic<Color3>();
  144. RegisterDynamic<Color>();
  145. RegisterDynamic<Vector4>();
  146. RegisterDynamic<Vector3>();
  147. RegisterDynamic<Vector2>();
  148. }
  149. /// <summary>
  150. /// Gets a tag value with the specified key.
  151. /// </summary>
  152. /// <param name="key">The tag key.</param>
  153. /// <returns>A tag value associated to a key</returns>
  154. public object GetTag(object key)
  155. {
  156. if (mapTag == null)
  157. return null;
  158. object value;
  159. mapTag.TryGetValue(key, out value);
  160. return value;
  161. }
  162. /// <summary>
  163. /// Determines whether a tag with a specified key is already stored.
  164. /// </summary>
  165. /// <param name="key">The key.</param>
  166. /// <returns><c>true</c> if a tag with a specified key is already stored; otherwise, <c>false</c>.</returns>
  167. public bool HasTag(object key)
  168. {
  169. if (mapTag == null)
  170. return false;
  171. return mapTag.ContainsKey(key);
  172. }
  173. /// <summary>
  174. /// Removes a tag with the specified key.
  175. /// </summary>
  176. /// <param name="key">The key.</param>
  177. public void RemoveTag(object key)
  178. {
  179. if (mapTag == null)
  180. return;
  181. mapTag.Remove(key);
  182. }
  183. /// <summary>
  184. /// Sets a tag value with the specified key.
  185. /// </summary>
  186. /// <param name="key">The key.</param>
  187. /// <param name="value">The value.</param>
  188. /// <returns></returns>
  189. public void SetTag(object key, object value)
  190. {
  191. if (mapTag == null)
  192. mapTag = new Dictionary<object, object>();
  193. // Always remove previous key before inserting new one
  194. mapTag.Remove(key);
  195. mapTag.Add(key, value);
  196. }
  197. /// <summary>
  198. /// Gets or sets the serialization mode.
  199. /// </summary>
  200. /// <value>The serialization mode.</value>
  201. public SerializerMode Mode
  202. {
  203. get { return mode; }
  204. set
  205. {
  206. mode = value;
  207. // Create Reader or writer
  208. if (Mode == SerializerMode.Read)
  209. {
  210. Reader = Reader ?? new BinaryReader(Stream);
  211. }
  212. else
  213. {
  214. Writer = Writer ?? new BinaryWriter(Stream);
  215. }
  216. }
  217. }
  218. /// <summary>
  219. /// Gets or sets the encoding used to serialized strings.
  220. /// </summary>
  221. /// <value>The encoding.</value>
  222. /// <exception cref="System.ArgumentNullException">When setting a null encoding</exception>
  223. public System.Text.Encoding Encoding
  224. {
  225. get { return encoding; }
  226. set {
  227. if (ReferenceEquals(value, null))
  228. throw new ArgumentNullException("value");
  229. if (!ReferenceEquals(encoding, value))
  230. {
  231. encoding = value;
  232. encoder = encoding.GetEncoder();
  233. decoder = encoding.GetDecoder();
  234. maxCharSize = encoding.GetMaxCharCount(LargeByteBufferSize);
  235. }
  236. }
  237. }
  238. /// <summary>
  239. /// Enables to serialize an object only once using object reference. Default is <strong>false</strong>.
  240. /// </summary>
  241. /// <value><c>true</c> if [allow null]; otherwise, <c>false</c>.</value>
  242. /// <exception cref="System.InvalidOperationException">If an invalid matching pair of true/false is detected.</exception>
  243. public bool AllowIdentity
  244. {
  245. get { return allowIdentityReferenceCount > 0; }
  246. set
  247. {
  248. allowIdentityReferenceCount += value ? 1 : -1;
  249. if (allowIdentityReferenceCount < 0)
  250. throw new InvalidOperationException("Invalid call to AllowIdentity. Must match true/false in pair.");
  251. }
  252. }
  253. /// <summary>
  254. /// Register a dynamic serializer for a particular type implementing the <see cref="IDataSerializable"/> interface and having the <see cref="DynamicSerializerAttribute"/>.
  255. /// </summary>
  256. /// <typeparam name="T">Type of the element to serialize.</typeparam>
  257. public void RegisterDynamic<T>() where T : IDataSerializable, new()
  258. {
  259. #if W8CORE
  260. var attribute = Utilities.GetCustomAttribute<DynamicSerializerAttribute>(typeof (T).GetTypeInfo());
  261. #else
  262. var attribute = Utilities.GetCustomAttribute<DynamicSerializerAttribute>(typeof (T));
  263. #endif
  264. if (attribute == null)
  265. throw new ArgumentException("Type T doesn't have DynamicSerializerAttribute", "T");
  266. RegisterDynamic<T>(attribute.Id);
  267. }
  268. /// <summary>
  269. /// Register a dynamic serializer for a particular type implementing the <see cref="IDataSerializable"/> interface.
  270. /// </summary>
  271. /// <typeparam name="T">Type of the element to serialize.</typeparam>
  272. /// <param name="id">The id to use for serializing T.</param>
  273. public void RegisterDynamic<T>(FourCC id) where T : IDataSerializable, new()
  274. {
  275. RegisterDynamic(GetDynamic<T>(id));
  276. }
  277. /// <summary>
  278. /// Register a dynamic array serializer for a particular type implementing the <see cref="IDataSerializable"/> interface.
  279. /// </summary>
  280. /// <typeparam name="T">Type of the element in the array.</typeparam>
  281. /// <param name="id">The id to use for serializing T[].</param>
  282. public void RegisterDynamicArray<T>(FourCC id) where T : IDataSerializable, new()
  283. {
  284. RegisterDynamic(GetDynamicArray<T>(id));
  285. }
  286. /// <summary>
  287. /// Register a dynamic List&lt;T&gt; serializer for a particular type implementing the <see cref="IDataSerializable"/> interface.
  288. /// </summary>
  289. /// <typeparam name="T">Type of the element in the List&lt;T&gt;.</typeparam>
  290. /// <param name="id">The id to use for serializing List&lt;T&gt;.</param>
  291. public void RegisterDynamicList<T>(FourCC id) where T : IDataSerializable, new()
  292. {
  293. RegisterDynamic(GetDynamicList<T>(id));
  294. }
  295. /// <summary>
  296. /// Register a dynamic serializer using an external action.
  297. /// </summary>
  298. /// <typeparam name="T">Type of the element to serialize.</typeparam>
  299. /// <param name="id">The id to use for serializing T.</param>
  300. /// <param name="serializer">The serializer.</param>
  301. public void RegisterDynamic<T>(FourCC id, SerializerAction serializer) where T : new()
  302. {
  303. var dynamicSerializer = new Dynamic {Id = id, Type = typeof (T), DynamicSerializer = serializer};
  304. dynamicSerializer.Reader = dynamicSerializer.DynamicReader<T>;
  305. dynamicSerializer.Writer = dynamicSerializer.DynamicWriter;
  306. RegisterDynamic(dynamicSerializer);
  307. }
  308. /// <summary>
  309. /// Begin to serialize a a new chunk.
  310. /// </summary>
  311. /// <param name="chunkId">The chunk id.</param>
  312. /// <exception cref="SharpDX.Serialization.InvalidChunkException">If the chuck to read is not the expecting chunk.</exception>
  313. /// <remarks>
  314. /// A Chunk is an identifiable portion of data that will serialized. Chunk are useful to encapsulate a variable
  315. /// data (and check for the presence of the chunk Id). Chunk are storing a 4 bytes identifier and the length of
  316. /// the chunk before reading/writing actual data.
  317. /// </remarks>
  318. public void BeginChunk(FourCC chunkId)
  319. {
  320. // Allocate new Chunk
  321. if (chunks[chunkCount] == null)
  322. {
  323. CurrentChunk = new Chunk();
  324. chunks[chunkCount] = CurrentChunk;
  325. }
  326. else
  327. {
  328. CurrentChunk = chunks[chunkCount];
  329. }
  330. // Go to next chunk
  331. chunkCount++;
  332. // Sets the current id
  333. CurrentChunk.Id = chunkId;
  334. // Create a new chunk
  335. if (Mode == SerializerMode.Write)
  336. CurrentChunk.ChunkIndexStart = Stream.Position;
  337. if (chunkCount >= chunks.Length)
  338. {
  339. var temp = new Chunk[chunks.Length * 2];
  340. Array.Copy(chunks, temp, chunks.Length);
  341. chunks = temp;
  342. }
  343. if (Mode == SerializerMode.Write)
  344. {
  345. // Write the chunkId to the current chunk
  346. Writer.Write((int) chunkId);
  347. // write temporary null size
  348. Writer.Write(0);
  349. }
  350. else
  351. {
  352. var chunkIdRead = Reader.ReadInt32();
  353. if (chunkIdRead != chunkId)
  354. throw new InvalidChunkException(chunkIdRead, chunkId);
  355. uint sizeOfChunk = (uint)Reader.ReadUInt32();
  356. CurrentChunk.ChunkIndexEnd = Stream.Position + sizeOfChunk;
  357. }
  358. }
  359. /// <summary>
  360. /// Ends a chunk.
  361. /// </summary>
  362. /// <exception cref="System.InvalidOperationException">If there EndChunk is called without a previous BeginChunk.</exception>
  363. /// <exception cref="System.IO.InvalidDataException">If the size of data read from the chunk is different from chunk size.</exception>
  364. public void EndChunk()
  365. {
  366. if (chunkCount <= 1)
  367. throw new InvalidOperationException("EndChunk() called without BeginChunk()");
  368. var previousChunk = CurrentChunk;
  369. chunkCount--;
  370. CurrentChunk = chunks[chunkCount - 1];
  371. if (Mode == SerializerMode.Write)
  372. {
  373. // Write the size of this chunk
  374. long currentPosition = Stream.Position;
  375. Stream.Position = previousChunk.ChunkIndexStart + 4;
  376. Writer.Write((uint)(currentPosition - Stream.Position - 4));
  377. Stream.Position = currentPosition;
  378. }
  379. else
  380. {
  381. if (previousChunk.ChunkIndexEnd != Stream.Position)
  382. throw new IOException(string.Format("Unexpected size when reading chunk [{0}]", CurrentChunk.Id));
  383. }
  384. }
  385. /// <summary>
  386. /// Deserialize a data from the underlying stream.
  387. /// </summary>
  388. /// <typeparam name="T">Type of the data to load.</typeparam>
  389. /// <returns>An instance of the loaded data.</returns>
  390. public T Load<T>() where T : IDataSerializable, new()
  391. {
  392. ResetStoredReference();
  393. Mode = SerializerMode.Read;
  394. T value = default(T);
  395. Serialize(ref value);
  396. return value;
  397. }
  398. /// <summary>
  399. /// Serializes the specified value to the underlying stream.
  400. /// </summary>
  401. /// <typeparam name="T">Type of the data to save.</typeparam>
  402. /// <param name="value">The value to save.</param>
  403. public void Save<T>(T value) where T : IDataSerializable, new()
  404. {
  405. ResetStoredReference();
  406. Mode = SerializerMode.Write;
  407. Serialize(ref value);
  408. Flush();
  409. }
  410. /// <summary>
  411. /// Flush the underlying <see cref="System.IO.Stream"/>
  412. /// </summary>
  413. public void Flush()
  414. {
  415. Writer.Flush();
  416. }
  417. /// <summary>
  418. /// Serializes a dynamic value that can be nullable.
  419. /// </summary>
  420. /// <typeparam name="T">Known type of the value to serialize. The known type is not the runtime type that will be actually serialized.</typeparam>
  421. /// <param name="value">The value to serialize based on its runtime type.</param>
  422. public void SerializeDynamic<T>(ref T value)
  423. {
  424. SerializeDynamic(ref value, SerializeFlags.Dynamic | SerializeFlags.Nullable);
  425. }
  426. /// <summary>
  427. /// Serializes a dynamic value.
  428. /// </summary>
  429. /// <typeparam name="T">Known type of the value to serialize. The known type is not the runtime type that will be actually serialized.</typeparam>
  430. /// <param name="value">The value to serialize based on its runtime type.</param>
  431. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  432. public void SerializeDynamic<T>(ref T value, SerializeFlags serializeFlags)
  433. {
  434. int storeObjectRef;
  435. if (SerializeIsNull(ref value, out storeObjectRef, serializeFlags | SerializeFlags.Dynamic))
  436. return;
  437. SerializeRawDynamic(ref value);
  438. }
  439. /// <summary>
  440. /// Serializes a static value implementing the <see cref="IDataSerializable"/> interface.
  441. /// </summary>
  442. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  443. /// <param name="value">The value to serialize</param>
  444. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  445. /// <remarks>
  446. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  447. /// </remarks>
  448. public void Serialize<T>(ref T value, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
  449. {
  450. int storeObjectRef;
  451. if (SerializeIsNull(ref value, out storeObjectRef, serializeFlags))
  452. return;
  453. if (Mode == SerializerMode.Read)
  454. value = new T();
  455. // Store ObjectRef
  456. if (storeObjectRef >= 0) StoreObjectRef(value, storeObjectRef);
  457. value.Serialize(this);
  458. }
  459. /// <summary>
  460. /// Serializes a static value implementing the <see cref="IDataSerializable"/> interface. Unlike <see cref="Serialize{T}(ref T)"/>,
  461. /// this method doesn't allocate a new instance when reading but use the reference value.
  462. /// </summary>
  463. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  464. /// <param name="value">The value to serialize</param>
  465. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  466. /// <remarks>
  467. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  468. /// </remarks>
  469. public void SerializeWithNoInstance<T>(ref T value, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable
  470. {
  471. int storeObjectRef;
  472. if (SerializeIsNull(ref value, out storeObjectRef, serializeFlags))
  473. return;
  474. // Store ObjectRef
  475. if (storeObjectRef >= 0) StoreObjectRef(value, storeObjectRef);
  476. value.Serialize(this);
  477. }
  478. /// <summary>
  479. /// Serializes an enum value.
  480. /// </summary>
  481. /// <typeparam name="T">Type of the enum to serialize.</typeparam>
  482. /// <param name="value">The value to serialize</param>
  483. /// <exception cref="ArgumentException">If type T is not an enum.</exception>
  484. /// <remarks>
  485. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  486. /// </remarks>
  487. public unsafe void SerializeEnum<T>(ref T value) where T : struct, IComparable, IFormattable
  488. {
  489. if (!Utilities.IsEnum(typeof(T)))
  490. throw new ArgumentException("T generic parameter must be a valid enum", "value");
  491. var pValue = Interop.Fixed(ref value);
  492. switch (Utilities.SizeOf<T>())
  493. {
  494. case 1:
  495. {
  496. Serialize(ref *(byte*)pValue);
  497. break;
  498. }
  499. case 2:
  500. {
  501. Serialize(ref *(short*)pValue);
  502. break;
  503. }
  504. case 4:
  505. {
  506. Serialize(ref *(int*)pValue);
  507. break;
  508. }
  509. case 8:
  510. {
  511. Serialize(ref *(long*)pValue);
  512. break;
  513. }
  514. }
  515. }
  516. /// <summary>
  517. /// Serializes an array of primitives using serialization methods implemented by this instance for each item in the array.
  518. /// </summary>
  519. /// <typeparam name="T">Type of the primitive data to serialize.</typeparam>
  520. /// <param name="valueArray">An array of primitive value to serialize</param>
  521. /// <param name="serializer">The serializer to user to serialize the T values.</param>
  522. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  523. /// <remarks>
  524. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  525. /// </remarks>
  526. public void Serialize<T>(ref T[] valueArray, SerializerPrimitiveAction<T> serializer, SerializeFlags serializeFlags = SerializeFlags.Normal)
  527. {
  528. int storeObjectRef;
  529. if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
  530. return;
  531. if (Mode == SerializerMode.Write)
  532. {
  533. // Store ObjectRef
  534. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  535. WriteArrayLength((int)valueArray.Length);
  536. for (int i = 0; i < valueArray.Length; i++)
  537. serializer(ref valueArray[i]);
  538. }
  539. else
  540. {
  541. var count = ReadArrayLength();
  542. valueArray = new T[count];
  543. // Store ObjectRef
  544. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  545. for (int index = 0; index < count; index++)
  546. serializer(ref valueArray[index]);
  547. }
  548. }
  549. /// <summary>
  550. /// Serializes count elements in an array of primitives using serialization methods implemented by this instance for each item in the array.
  551. /// </summary>
  552. /// <typeparam name="T">Type of the primitive data to serialize.</typeparam>
  553. /// <param name="valueArray">An array of primitive value to serialize</param>
  554. /// <param name="count">Count elements to serialize. See remarks.</param>
  555. /// <param name="serializer">The serializer to user to serialize the T values.</param>
  556. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  557. /// <remarks>
  558. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
  559. /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
  560. /// when we want to serialize the count of an array separately from the array.
  561. /// </remarks>
  562. public void Serialize<T>(ref T[] valueArray, int count, SerializerPrimitiveAction<T> serializer, SerializeFlags serializeFlags = SerializeFlags.Normal)
  563. {
  564. int storeObjectRef;
  565. if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
  566. return;
  567. if (Mode == SerializerMode.Write)
  568. {
  569. // Store ObjectRef
  570. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  571. for (int i = 0; i < count; i++)
  572. serializer(ref valueArray[i]);
  573. }
  574. else
  575. {
  576. valueArray = new T[count];
  577. // Store ObjectRef
  578. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  579. for (int index = 0; index < count; index++)
  580. serializer(ref valueArray[index]);
  581. }
  582. }
  583. /// <summary>
  584. /// Serializes an array of static values that are implementing the <see cref="IDataSerializable"/> interface.
  585. /// </summary>
  586. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  587. /// <param name="valueArray">An array of value to serialize</param>
  588. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  589. /// <remarks>
  590. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  591. /// </remarks>
  592. public void Serialize<T>(ref T[] valueArray, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
  593. {
  594. int storeObjectRef;
  595. if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
  596. return;
  597. if (Mode == SerializerMode.Write)
  598. {
  599. // Store ObjectRef
  600. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  601. WriteArrayLength(valueArray.Length);
  602. for (int i = 0; i < valueArray.Length; i++)
  603. Serialize(ref valueArray[i], serializeFlags);
  604. }
  605. else
  606. {
  607. var count = ReadArrayLength();
  608. valueArray = new T[count];
  609. // Store ObjectRef
  610. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  611. for (int index = 0; index < count; index++)
  612. Serialize(ref valueArray[index], serializeFlags);
  613. }
  614. }
  615. /// <summary>
  616. /// Serializes an array of static values that are implementing the <see cref="IDataSerializable"/> interface.
  617. /// </summary>
  618. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  619. /// <param name="valueArray">An array of value to serialize</param>
  620. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  621. /// <remarks>
  622. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  623. /// </remarks>
  624. public void SerializeWithNoInstance<T>(ref T[] valueArray, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable
  625. {
  626. int storeObjectRef;
  627. if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
  628. return;
  629. if (Mode == SerializerMode.Write)
  630. {
  631. // Store ObjectRef
  632. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  633. WriteArrayLength(valueArray.Length);
  634. for (int i = 0; i < valueArray.Length; i++)
  635. SerializeWithNoInstance(ref valueArray[i], serializeFlags);
  636. }
  637. else
  638. {
  639. var count = ReadArrayLength();
  640. valueArray = new T[count];
  641. // Store ObjectRef
  642. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  643. for (int index = 0; index < count; index++)
  644. SerializeWithNoInstance(ref valueArray[index], serializeFlags);
  645. }
  646. }
  647. /// <summary>
  648. /// Serializes count elements in an array of static values that are implementing the <see cref="IDataSerializable"/> interface.
  649. /// </summary>
  650. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  651. /// <param name="valueArray">An array of value to serialize</param>
  652. /// <param name="count">Count elements to serialize. See remarks.</param>
  653. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  654. /// <remarks>
  655. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
  656. /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
  657. /// when we want to serialize the count of an array separately from the array.
  658. /// </remarks>
  659. public void Serialize<T>(ref T[] valueArray, int count, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
  660. {
  661. int storeObjectRef;
  662. if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
  663. return;
  664. if (Mode == SerializerMode.Write)
  665. {
  666. // Store ObjectRef
  667. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  668. for (int i = 0; i < count; i++)
  669. Serialize(ref valueArray[i], serializeFlags);
  670. }
  671. else
  672. {
  673. valueArray = new T[count];
  674. // Store ObjectRef
  675. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  676. for (int index = 0; index < count; index++)
  677. Serialize(ref valueArray[index], serializeFlags);
  678. }
  679. }
  680. /// <summary>
  681. /// Serializes an array of bytes.
  682. /// </summary>
  683. /// <param name="valueArray">An array of bytes to serialize</param>
  684. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  685. /// <remarks>
  686. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  687. /// </remarks>
  688. public void Serialize(ref byte[] valueArray, SerializeFlags serializeFlags = SerializeFlags.Normal)
  689. {
  690. int storeObjectRef;
  691. if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
  692. return;
  693. if (Mode == SerializerMode.Write)
  694. {
  695. // Store ObjectRef
  696. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  697. WriteArrayLength(valueArray.Length);
  698. Writer.Write(valueArray);
  699. }
  700. else
  701. {
  702. int count = ReadArrayLength();
  703. valueArray = new byte[count];
  704. // Store ObjectRef
  705. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  706. Reader.Read(valueArray, 0, count);
  707. }
  708. }
  709. /// <summary>
  710. /// Serializes an array of bytes.
  711. /// </summary>
  712. /// <param name="valueArray">An array of bytes to serialize</param>
  713. /// <param name="count">Count elements to serialize. See remarks.</param>
  714. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  715. /// <remarks>
  716. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
  717. /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
  718. /// when we want to serialize the count of an array separately from the array.
  719. /// </remarks>
  720. public void Serialize(ref byte[] valueArray, int count, SerializeFlags serializeFlags = SerializeFlags.Normal)
  721. {
  722. int storeObjectRef;
  723. if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
  724. return;
  725. if (Mode == SerializerMode.Write)
  726. {
  727. // Store ObjectRef
  728. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  729. Writer.Write(valueArray, 0, count);
  730. }
  731. else
  732. {
  733. valueArray = new byte[count];
  734. // Store ObjectRef
  735. if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
  736. Reader.Read(valueArray, 0, count);
  737. }
  738. }
  739. /// <summary>
  740. /// Serializes a list of static values that are implementing the <see cref="IDataSerializable"/> interface.
  741. /// </summary>
  742. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  743. /// <param name="valueList">A list of value to serialize</param>
  744. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  745. /// <remarks>
  746. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  747. /// </remarks>
  748. public void Serialize<T>(ref List<T> valueList, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
  749. {
  750. int storeObjectRef;
  751. if (SerializeIsNull(ref valueList, out storeObjectRef, serializeFlags))
  752. return;
  753. if (Mode == SerializerMode.Write)
  754. {
  755. // Store ObjectRef
  756. if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
  757. WriteArrayLength(valueList.Count);
  758. foreach (var value in valueList)
  759. {
  760. T localValue = value;
  761. Serialize(ref localValue);
  762. }
  763. }
  764. else
  765. {
  766. var count = ReadArrayLength();
  767. valueList = new List<T>(count);
  768. // Store ObjectRef
  769. if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
  770. for (int index = 0; index < count; index++)
  771. {
  772. var value = default(T);
  773. Serialize(ref value);
  774. valueList.Add(value);
  775. }
  776. }
  777. }
  778. /// <summary>
  779. /// Serializes a list of static values that are implementing the <see cref="IDataSerializable"/> interface.
  780. /// </summary>
  781. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  782. /// <param name="valueList">A list of value to serialize</param>
  783. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  784. /// <remarks>
  785. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  786. /// </remarks>
  787. public void SerializeThis<T>(List<T> valueList, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
  788. {
  789. if (Mode == SerializerMode.Write)
  790. {
  791. WriteArrayLength(valueList.Count);
  792. foreach (var value in valueList)
  793. {
  794. T localValue = value;
  795. Serialize(ref localValue);
  796. }
  797. }
  798. else
  799. {
  800. var count = ReadArrayLength();
  801. for (int index = 0; index < count; index++)
  802. {
  803. var value = default(T);
  804. Serialize(ref value);
  805. valueList.Add(value);
  806. }
  807. }
  808. }
  809. /// <summary>
  810. /// Serializes a list of primitive values using a specific serializer method from this instance.
  811. /// </summary>
  812. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  813. /// <param name="valueList">A list of value to serialize</param>
  814. /// <param name="serializerMethod">A method of this instance to serialize the primitive T type</param>
  815. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  816. /// <remarks>
  817. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  818. /// </remarks>
  819. public void Serialize<T>(ref List<T> valueList, SerializerPrimitiveAction<T> serializerMethod, SerializeFlags serializeFlags = SerializeFlags.Normal)
  820. {
  821. int storeObjectRef;
  822. if (SerializeIsNull(ref valueList, out storeObjectRef, serializeFlags))
  823. return;
  824. if (Mode == SerializerMode.Write)
  825. {
  826. // Store ObjectRef
  827. if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
  828. WriteArrayLength(valueList.Count);
  829. foreach (var value in valueList)
  830. {
  831. T localValue = value;
  832. serializerMethod(ref localValue);
  833. }
  834. }
  835. else
  836. {
  837. var count = ReadArrayLength();
  838. EnsureList(ref valueList, count);
  839. // Store ObjectRef
  840. if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
  841. for (int i = 0; i < count; i++)
  842. {
  843. var localValue = default(T);
  844. serializerMethod(ref localValue);
  845. valueList.Add(localValue);
  846. }
  847. }
  848. }
  849. /// <summary>
  850. /// Serializes count elements from a list of static values that are implementing the <see cref="IDataSerializable"/> interface.
  851. /// </summary>
  852. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  853. /// <param name="valueList">A list of value to serialize</param>
  854. /// <param name="count">Count elements to serialize. See remarks.</param>
  855. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  856. /// <remarks>
  857. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
  858. /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
  859. /// when we want to serialize the count of an array separately from the array.
  860. /// </remarks>
  861. public void Serialize<T>(ref List<T> valueList, int count, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
  862. {
  863. int storeObjectRef;
  864. if (SerializeIsNull(ref valueList, out storeObjectRef, serializeFlags))
  865. return;
  866. if (Mode == SerializerMode.Write)
  867. {
  868. // Store ObjectRef
  869. if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
  870. for (int i = 0; i < count; i++)
  871. {
  872. T localValue = valueList[i];
  873. Serialize(ref localValue, serializeFlags);
  874. }
  875. }
  876. else
  877. {
  878. EnsureList(ref valueList, count);
  879. // Store ObjectRef
  880. if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
  881. for (int index = 0; index < count; index++)
  882. {
  883. var value = default(T);
  884. Serialize(ref value, serializeFlags);
  885. valueList.Add(value);
  886. }
  887. }
  888. }
  889. /// <summary>
  890. /// Serializes count elements from a list of primitive values using a specific serializer method from this instance.
  891. /// </summary>
  892. /// <typeparam name="T">Type of the data to serialize.</typeparam>
  893. /// <param name="valueList">A list of value to serialize</param>
  894. /// <param name="serializerMethod">A method of this instance to serialize the primitive T type</param>
  895. /// <param name="count">Count elements to serialize. See remarks.</param>
  896. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  897. /// <remarks>
  898. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
  899. /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
  900. /// when we want to serialize the count of an array separately from the array.
  901. /// </remarks>
  902. public void Serialize<T>(ref List<T> valueList, int count, SerializerPrimitiveAction<T> serializerMethod, SerializeFlags serializeFlags = SerializeFlags.Normal)
  903. {
  904. int storeObjectRef;
  905. if (SerializeIsNull(ref valueList, out storeObjectRef, serializeFlags))
  906. return;
  907. if (Mode == SerializerMode.Write)
  908. {
  909. // Store ObjectRef
  910. if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
  911. for (int i = 0; i < count; i++)
  912. {
  913. T localValue = valueList[i];
  914. serializerMethod(ref localValue);
  915. }
  916. }
  917. else
  918. {
  919. EnsureList(ref valueList, count);
  920. // Store ObjectRef
  921. if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
  922. for (int i = 0; i < count; i++)
  923. {
  924. var localValue = default(T);
  925. serializerMethod(ref localValue);
  926. valueList.Add(localValue);
  927. }
  928. }
  929. }
  930. private void EnsureList<T>(ref List<T> valueList, int count)
  931. {
  932. // If there is a list provided, use it in place instead of allocating a new one
  933. if (valueList != null)
  934. {
  935. valueList.Clear();
  936. if (valueList.Capacity < count)
  937. {
  938. valueList.Capacity = count;
  939. }
  940. }
  941. else
  942. {
  943. valueList = new List<T>(count);
  944. }
  945. }
  946. /// <summary>
  947. /// Serializes a dictionary of key/values that are both implementing the <see cref="IDataSerializable"/> interface.
  948. /// </summary>
  949. /// <typeparam name="TKey">Type of key to serialize.</typeparam>
  950. /// <typeparam name="TValue">Type of value to serialize.</typeparam>
  951. /// <param name="dictionary">A dictionary to serialize</param>
  952. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  953. /// <remarks>
  954. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  955. /// </remarks>
  956. public void Serialize<TKey, TValue>(ref Dictionary<TKey, TValue> dictionary, SerializeFlags serializeFlags = SerializeFlags.Normal)
  957. where TKey : IDataSerializable, new()
  958. where TValue : IDataSerializable, new()
  959. {
  960. int storeObjectRef;
  961. if (SerializeIsNull(ref dictionary, out storeObjectRef, serializeFlags))
  962. return;
  963. if (Mode == SerializerMode.Write)
  964. {
  965. // Store ObjectRef
  966. if (storeObjectRef >= 0) StoreObjectRef(dictionary, storeObjectRef);
  967. WriteArrayLength(dictionary.Count);
  968. foreach (var value in dictionary)
  969. {
  970. TKey localKey = value.Key;
  971. TValue localValue = value.Value;
  972. localKey.Serialize(this);
  973. localValue.Serialize(this);
  974. }
  975. }
  976. else
  977. {
  978. var count = ReadArrayLength();
  979. dictionary = new Dictionary<TKey, TValue>(count);
  980. // Store ObjectRef
  981. if (storeObjectRef >= 0) StoreObjectRef(dictionary, storeObjectRef);
  982. for (int i = 0; i < count; i++)
  983. {
  984. TKey localKey = default(TKey);
  985. TValue localValue = default(TValue);
  986. localKey.Serialize(this);
  987. localValue.Serialize(this);
  988. dictionary.Add(localKey, localValue);
  989. }
  990. }
  991. }
  992. /// <summary>
  993. /// Serializes a dictionary of key/values.
  994. /// </summary>
  995. /// <typeparam name="TKey">Type of key to serialize that is implementing the <see cref="IDataSerializable"/> interface.</typeparam>
  996. /// <typeparam name="TValue">Type of primitive value with its associated serializer.</typeparam>
  997. /// <param name="dictionary">A dictionary to serialize</param>
  998. /// <param name="valueSerializer">Serializer used for the TValue.</param>
  999. /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
  1000. /// <remarks>
  1001. /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
  1002. /// </remarks>
  1003. public void Serialize<TKey, TValue>(ref Dictionary<TKey, TValue> dictionary, SerializerPrimitiveAction<TValue> valueSerializer, SerializeFlags serializeFlags = SerializeFlags.Normal) where TKey : IDataSerializable, new()
  1004. {
  1005. int storeObjectRef;
  1006. if (SerializeIsNull(ref dictionary, out storeObjectRef, serializeFlags))
  1007. return;
  1008. if (Mode == SerializerMode.Write)
  1009. {
  1010. // Store ObjectRef
  1011. if (storeObjectRef >= 0) StoreObjectRef(dictionary, storeObjectRef);
  1012. WriteArrayLength(dictionary.Count);
  1013. foreach (var value in dictionary)
  1014. {
  1015. TKey localKey = value.Key;
  1016. TValue localValue = value.Value;
  1017. localKey.Serialize(this);
  1018. valueSerializer(ref localValue);
  1019. }
  1020. }
  1021. else
  1022. {
  1023. var count = ReadArrayLength();
  1024. dictionary = new Dictionary<TKey, TValue>(count);
  1025. // Store ObjectRef
  1026. if (storeObjectRef >= 0) StoreObjectRef(dictionary, storeObjectRef);
  1027. for (int i = 0; i < count; i++)
  1028. {
  1029. TKey localKey = default(TKey);
  1030. TValue localValue = default(TValue);
  1031. localKey.Serialize(this);
  1032. valueSerializer(ref localValue);

Large files files are truncated, but you can click here to view the full file