/Source/SharpDX/Serialization/BinarySerializer.cs
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
- // Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Text;
- using SharpDX.IO;
- using SharpDX.Multimedia;
- using System.Reflection;
- namespace SharpDX.Serialization
- {
- /// <summary>
- /// Serializer action.
- /// </summary>
- /// <param name="value">The value to read or write.</param>
- /// <param name="serializer">The serializer.</param>
- public delegate void SerializerAction(ref object value, BinarySerializer serializer);
- /// <summary>
- /// This class provides serialization methods for types implementing the <see cref="IDataSerializable"/>.
- /// </summary>
- /// <remarks>
- /// BinarySerializer is a basic binary serializer with the following features:
- /// <ul>
- /// <li>10x times faster and smaller than default System Serialization and Xml Serialization.</li>
- /// <li>Supports for all primitive types, array/List<T>/Dictionary of primitive types, custom data via <see cref="IDataSerializable"/> (struct or class) and array/List/Dictionary of custom data.</li>
- /// <li>Optimized binary format, data serialized to the strict minimum.</li>
- /// <li>Should be compatible with Win8/WinRT, Desktop.</li>
- /// <li>Not reflection based serializer, but fully compile time serializer.</li>
- /// <li>Format could be read back from C/C++.</li>
- ///
- /// </ul>
- /// </remarks>
- public class BinarySerializer : Component
- {
- private int chunkCount;
- private Chunk[] chunks;
- private Chunk currentChunk;
- private readonly Dictionary<FourCC, Dynamic> dynamicMapToType;
- private readonly Dictionary<Type, Dynamic> dynamicMapToFourCC;
- private readonly Dictionary<object, int> objectToPosition;
- private readonly Dictionary<int, object> positionToObject;
- private Dictionary<object, object> mapTag;
- private int allowIdentityReferenceCount;
- // Fields used to serialize strings
- private System.Text.Encoding encoding;
- private System.Text.Encoder encoder;
- private System.Text.Decoder decoder;
- private const int LargeByteBufferSize = 1024;
- private byte[] largeByteBuffer;
- private int maxChars; // max # of chars we can put in _largeByteBuffer
- private char[] largeCharBuffer;
- private int maxCharSize; // From LargeByteBufferSize & Encoding
- public delegate void SerializerPrimitiveAction<T>(ref T value);
- public delegate void SerializerTypeAction<T>(ref T value, BinarySerializer serializer);
- public delegate object ReadRef(BinarySerializer serializer);
- public delegate void WriteRef(object value, BinarySerializer serializer);
- /// <summary>
- /// Underlying stream this instance is reading/writing to.
- /// </summary>
- public Stream Stream { get; private set; }
- /// <summary>
- /// Reader used to directly read from the underlying stream.
- /// </summary>
- public BinaryReader Reader { get; private set; }
- /// <summary>
- /// Gets the reader and throws an exception if this serializer is in Write mode.
- /// </summary>
- /// <param name="context">The context object that requires a Reader.</param>
- /// <returns>A BinaryReader.</returns>
- /// <exception cref="System.ArgumentNullException">context</exception>
- /// <exception cref="System.InvalidOperationException">If this reader is not in read mode</exception>
- public BinaryReader ReaderOnly(object context)
- {
- if (context == null)
- {
- throw new ArgumentNullException("context");
- }
- if (Mode != SerializerMode.Read)
- {
- throw new InvalidOperationException(string.Format("[{0}] is only expecting Read-Only BinarySerializer", context.GetType().Name));
- }
- return Reader;
- }
- /// <summary>
- /// Writer used to directly write to the underlying stream.
- /// </summary>
- public BinaryWriter Writer { get; private set; }
- public ArrayLengthType ArrayLengthType { get; set; }
- private SerializerMode mode;
- /// <summary>
- /// Initializes a new instance of the <see cref="BinarySerializer" /> class.
- /// </summary>
- /// <param name="stream">The stream to read or write to.</param>
- /// <param name="mode">The read or write mode.</param>
- public BinarySerializer(Stream stream, SerializerMode mode) : this(stream, mode, SharpDX.Text.Encoding.ASCII)
- {
- }
- /// <summary>
- /// Initializes a new instance of the <see cref="BinarySerializer" /> class.
- /// </summary>
- /// <param name="stream">The stream to read or write to.</param>
- /// <param name="mode">The read or write mode.</param>
- /// <param name="encoding">Default encoding used for strings. This parameter can be overriden later using Encoding property.</param>
- public BinarySerializer(Stream stream, SerializerMode mode, System.Text.Encoding encoding)
- {
- // Setup the encoding used for strings.
- Encoding = encoding;
- // Allocate dictionary used for dynamic serialization.
- dynamicMapToType = new Dictionary<FourCC, Dynamic>();
- dynamicMapToFourCC = new Dictionary<Type, Dynamic>();
- // For serializing reference
- objectToPosition = new Dictionary<object, int>(new IdentityEqualityComparer<object>());
- positionToObject = new Dictionary<int, object>();
- // Allocate the chunk array and initial chunk.
- chunks = new Chunk[8];
- Stream = stream;
- // Setup the mode.
- Mode = mode;
- CurrentChunk = new Chunk { ChunkIndexStart = 0 };
- chunks[chunkCount] = CurrentChunk;
- chunkCount++;
- // Register all default dynamics.
- foreach (var defaultDynamic in DefaultDynamics)
- RegisterDynamic(defaultDynamic);
- RegisterDynamic<Color4>();
- RegisterDynamic<Color3>();
- RegisterDynamic<Color>();
- RegisterDynamic<Vector4>();
- RegisterDynamic<Vector3>();
- RegisterDynamic<Vector2>();
- }
- /// <summary>
- /// Gets a tag value with the specified key.
- /// </summary>
- /// <param name="key">The tag key.</param>
- /// <returns>A tag value associated to a key</returns>
- public object GetTag(object key)
- {
- if (mapTag == null)
- return null;
- object value;
- mapTag.TryGetValue(key, out value);
- return value;
- }
- /// <summary>
- /// Determines whether a tag with a specified key is already stored.
- /// </summary>
- /// <param name="key">The key.</param>
- /// <returns><c>true</c> if a tag with a specified key is already stored; otherwise, <c>false</c>.</returns>
- public bool HasTag(object key)
- {
- if (mapTag == null)
- return false;
- return mapTag.ContainsKey(key);
- }
- /// <summary>
- /// Removes a tag with the specified key.
- /// </summary>
- /// <param name="key">The key.</param>
- public void RemoveTag(object key)
- {
- if (mapTag == null)
- return;
- mapTag.Remove(key);
- }
- /// <summary>
- /// Sets a tag value with the specified key.
- /// </summary>
- /// <param name="key">The key.</param>
- /// <param name="value">The value.</param>
- /// <returns></returns>
- public void SetTag(object key, object value)
- {
- if (mapTag == null)
- mapTag = new Dictionary<object, object>();
- // Always remove previous key before inserting new one
- mapTag.Remove(key);
- mapTag.Add(key, value);
- }
- /// <summary>
- /// Gets or sets the serialization mode.
- /// </summary>
- /// <value>The serialization mode.</value>
- public SerializerMode Mode
- {
- get { return mode; }
- set
- {
- mode = value;
- // Create Reader or writer
- if (Mode == SerializerMode.Read)
- {
- Reader = Reader ?? new BinaryReader(Stream);
- }
- else
- {
- Writer = Writer ?? new BinaryWriter(Stream);
- }
- }
- }
- /// <summary>
- /// Gets or sets the encoding used to serialized strings.
- /// </summary>
- /// <value>The encoding.</value>
- /// <exception cref="System.ArgumentNullException">When setting a null encoding</exception>
- public System.Text.Encoding Encoding
- {
- get { return encoding; }
- set {
- if (ReferenceEquals(value, null))
- throw new ArgumentNullException("value");
- if (!ReferenceEquals(encoding, value))
- {
- encoding = value;
- encoder = encoding.GetEncoder();
- decoder = encoding.GetDecoder();
- maxCharSize = encoding.GetMaxCharCount(LargeByteBufferSize);
- }
- }
- }
- /// <summary>
- /// Enables to serialize an object only once using object reference. Default is <strong>false</strong>.
- /// </summary>
- /// <value><c>true</c> if [allow null]; otherwise, <c>false</c>.</value>
- /// <exception cref="System.InvalidOperationException">If an invalid matching pair of true/false is detected.</exception>
- public bool AllowIdentity
- {
- get { return allowIdentityReferenceCount > 0; }
- set
- {
- allowIdentityReferenceCount += value ? 1 : -1;
- if (allowIdentityReferenceCount < 0)
- throw new InvalidOperationException("Invalid call to AllowIdentity. Must match true/false in pair.");
- }
- }
- /// <summary>
- /// Register a dynamic serializer for a particular type implementing the <see cref="IDataSerializable"/> interface and having the <see cref="DynamicSerializerAttribute"/>.
- /// </summary>
- /// <typeparam name="T">Type of the element to serialize.</typeparam>
- public void RegisterDynamic<T>() where T : IDataSerializable, new()
- {
- #if W8CORE
- var attribute = Utilities.GetCustomAttribute<DynamicSerializerAttribute>(typeof (T).GetTypeInfo());
- #else
- var attribute = Utilities.GetCustomAttribute<DynamicSerializerAttribute>(typeof (T));
- #endif
- if (attribute == null)
- throw new ArgumentException("Type T doesn't have DynamicSerializerAttribute", "T");
- RegisterDynamic<T>(attribute.Id);
- }
- /// <summary>
- /// Register a dynamic serializer for a particular type implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the element to serialize.</typeparam>
- /// <param name="id">The id to use for serializing T.</param>
- public void RegisterDynamic<T>(FourCC id) where T : IDataSerializable, new()
- {
- RegisterDynamic(GetDynamic<T>(id));
- }
- /// <summary>
- /// Register a dynamic array serializer for a particular type implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the element in the array.</typeparam>
- /// <param name="id">The id to use for serializing T[].</param>
- public void RegisterDynamicArray<T>(FourCC id) where T : IDataSerializable, new()
- {
- RegisterDynamic(GetDynamicArray<T>(id));
- }
- /// <summary>
- /// Register a dynamic List<T> serializer for a particular type implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the element in the List<T>.</typeparam>
- /// <param name="id">The id to use for serializing List<T>.</param>
- public void RegisterDynamicList<T>(FourCC id) where T : IDataSerializable, new()
- {
- RegisterDynamic(GetDynamicList<T>(id));
- }
-
- /// <summary>
- /// Register a dynamic serializer using an external action.
- /// </summary>
- /// <typeparam name="T">Type of the element to serialize.</typeparam>
- /// <param name="id">The id to use for serializing T.</param>
- /// <param name="serializer">The serializer.</param>
- public void RegisterDynamic<T>(FourCC id, SerializerAction serializer) where T : new()
- {
- var dynamicSerializer = new Dynamic {Id = id, Type = typeof (T), DynamicSerializer = serializer};
- dynamicSerializer.Reader = dynamicSerializer.DynamicReader<T>;
- dynamicSerializer.Writer = dynamicSerializer.DynamicWriter;
- RegisterDynamic(dynamicSerializer);
- }
- /// <summary>
- /// Begin to serialize a a new chunk.
- /// </summary>
- /// <param name="chunkId">The chunk id.</param>
- /// <exception cref="SharpDX.Serialization.InvalidChunkException">If the chuck to read is not the expecting chunk.</exception>
- /// <remarks>
- /// A Chunk is an identifiable portion of data that will serialized. Chunk are useful to encapsulate a variable
- /// data (and check for the presence of the chunk Id). Chunk are storing a 4 bytes identifier and the length of
- /// the chunk before reading/writing actual data.
- /// </remarks>
- public void BeginChunk(FourCC chunkId)
- {
- // Allocate new Chunk
- if (chunks[chunkCount] == null)
- {
- CurrentChunk = new Chunk();
- chunks[chunkCount] = CurrentChunk;
- }
- else
- {
- CurrentChunk = chunks[chunkCount];
- }
- // Go to next chunk
- chunkCount++;
- // Sets the current id
- CurrentChunk.Id = chunkId;
- // Create a new chunk
- if (Mode == SerializerMode.Write)
- CurrentChunk.ChunkIndexStart = Stream.Position;
- if (chunkCount >= chunks.Length)
- {
- var temp = new Chunk[chunks.Length * 2];
- Array.Copy(chunks, temp, chunks.Length);
- chunks = temp;
- }
- if (Mode == SerializerMode.Write)
- {
- // Write the chunkId to the current chunk
- Writer.Write((int) chunkId);
- // write temporary null size
- Writer.Write(0);
- }
- else
- {
- var chunkIdRead = Reader.ReadInt32();
- if (chunkIdRead != chunkId)
- throw new InvalidChunkException(chunkIdRead, chunkId);
- uint sizeOfChunk = (uint)Reader.ReadUInt32();
- CurrentChunk.ChunkIndexEnd = Stream.Position + sizeOfChunk;
- }
- }
- /// <summary>
- /// Ends a chunk.
- /// </summary>
- /// <exception cref="System.InvalidOperationException">If there EndChunk is called without a previous BeginChunk.</exception>
- /// <exception cref="System.IO.InvalidDataException">If the size of data read from the chunk is different from chunk size.</exception>
- public void EndChunk()
- {
- if (chunkCount <= 1)
- throw new InvalidOperationException("EndChunk() called without BeginChunk()");
- var previousChunk = CurrentChunk;
- chunkCount--;
- CurrentChunk = chunks[chunkCount - 1];
- if (Mode == SerializerMode.Write)
- {
- // Write the size of this chunk
- long currentPosition = Stream.Position;
- Stream.Position = previousChunk.ChunkIndexStart + 4;
- Writer.Write((uint)(currentPosition - Stream.Position - 4));
- Stream.Position = currentPosition;
- }
- else
- {
- if (previousChunk.ChunkIndexEnd != Stream.Position)
- throw new IOException(string.Format("Unexpected size when reading chunk [{0}]", CurrentChunk.Id));
- }
- }
- /// <summary>
- /// Deserialize a data from the underlying stream.
- /// </summary>
- /// <typeparam name="T">Type of the data to load.</typeparam>
- /// <returns>An instance of the loaded data.</returns>
- public T Load<T>() where T : IDataSerializable, new()
- {
- ResetStoredReference();
- Mode = SerializerMode.Read;
- T value = default(T);
- Serialize(ref value);
- return value;
- }
- /// <summary>
- /// Serializes the specified value to the underlying stream.
- /// </summary>
- /// <typeparam name="T">Type of the data to save.</typeparam>
- /// <param name="value">The value to save.</param>
- public void Save<T>(T value) where T : IDataSerializable, new()
- {
- ResetStoredReference();
- Mode = SerializerMode.Write;
- Serialize(ref value);
- Flush();
- }
- /// <summary>
- /// Flush the underlying <see cref="System.IO.Stream"/>
- /// </summary>
- public void Flush()
- {
- Writer.Flush();
- }
- /// <summary>
- /// Serializes a dynamic value that can be nullable.
- /// </summary>
- /// <typeparam name="T">Known type of the value to serialize. The known type is not the runtime type that will be actually serialized.</typeparam>
- /// <param name="value">The value to serialize based on its runtime type.</param>
- public void SerializeDynamic<T>(ref T value)
- {
- SerializeDynamic(ref value, SerializeFlags.Dynamic | SerializeFlags.Nullable);
- }
- /// <summary>
- /// Serializes a dynamic value.
- /// </summary>
- /// <typeparam name="T">Known type of the value to serialize. The known type is not the runtime type that will be actually serialized.</typeparam>
- /// <param name="value">The value to serialize based on its runtime type.</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- public void SerializeDynamic<T>(ref T value, SerializeFlags serializeFlags)
- {
- int storeObjectRef;
- if (SerializeIsNull(ref value, out storeObjectRef, serializeFlags | SerializeFlags.Dynamic))
- return;
- SerializeRawDynamic(ref value);
- }
- /// <summary>
- /// Serializes a static value implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="value">The value to serialize</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void Serialize<T>(ref T value, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
- {
- int storeObjectRef;
- if (SerializeIsNull(ref value, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Read)
- value = new T();
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(value, storeObjectRef);
- value.Serialize(this);
- }
- /// <summary>
- /// Serializes a static value implementing the <see cref="IDataSerializable"/> interface. Unlike <see cref="Serialize{T}(ref T)"/>,
- /// this method doesn't allocate a new instance when reading but use the reference value.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="value">The value to serialize</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void SerializeWithNoInstance<T>(ref T value, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable
- {
- int storeObjectRef;
- if (SerializeIsNull(ref value, out storeObjectRef, serializeFlags))
- return;
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(value, storeObjectRef);
- value.Serialize(this);
- }
- /// <summary>
- /// Serializes an enum value.
- /// </summary>
- /// <typeparam name="T">Type of the enum to serialize.</typeparam>
- /// <param name="value">The value to serialize</param>
- /// <exception cref="ArgumentException">If type T is not an enum.</exception>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public unsafe void SerializeEnum<T>(ref T value) where T : struct, IComparable, IFormattable
- {
- if (!Utilities.IsEnum(typeof(T)))
- throw new ArgumentException("T generic parameter must be a valid enum", "value");
- var pValue = Interop.Fixed(ref value);
- switch (Utilities.SizeOf<T>())
- {
- case 1:
- {
- Serialize(ref *(byte*)pValue);
- break;
- }
- case 2:
- {
- Serialize(ref *(short*)pValue);
- break;
- }
- case 4:
- {
- Serialize(ref *(int*)pValue);
- break;
- }
- case 8:
- {
- Serialize(ref *(long*)pValue);
- break;
- }
- }
- }
- /// <summary>
- /// Serializes an array of primitives using serialization methods implemented by this instance for each item in the array.
- /// </summary>
- /// <typeparam name="T">Type of the primitive data to serialize.</typeparam>
- /// <param name="valueArray">An array of primitive value to serialize</param>
- /// <param name="serializer">The serializer to user to serialize the T values.</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void Serialize<T>(ref T[] valueArray, SerializerPrimitiveAction<T> serializer, SerializeFlags serializeFlags = SerializeFlags.Normal)
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- WriteArrayLength((int)valueArray.Length);
- for (int i = 0; i < valueArray.Length; i++)
- serializer(ref valueArray[i]);
- }
- else
- {
- var count = ReadArrayLength();
- valueArray = new T[count];
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- for (int index = 0; index < count; index++)
- serializer(ref valueArray[index]);
- }
- }
- /// <summary>
- /// Serializes count elements in an array of primitives using serialization methods implemented by this instance for each item in the array.
- /// </summary>
- /// <typeparam name="T">Type of the primitive data to serialize.</typeparam>
- /// <param name="valueArray">An array of primitive value to serialize</param>
- /// <param name="count">Count elements to serialize. See remarks.</param>
- /// <param name="serializer">The serializer to user to serialize the T values.</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
- /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
- /// when we want to serialize the count of an array separately from the array.
- /// </remarks>
- public void Serialize<T>(ref T[] valueArray, int count, SerializerPrimitiveAction<T> serializer, SerializeFlags serializeFlags = SerializeFlags.Normal)
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- for (int i = 0; i < count; i++)
- serializer(ref valueArray[i]);
- }
- else
- {
- valueArray = new T[count];
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
-
- for (int index = 0; index < count; index++)
- serializer(ref valueArray[index]);
- }
- }
-
- /// <summary>
- /// Serializes an array of static values that are implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="valueArray">An array of value to serialize</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void Serialize<T>(ref T[] valueArray, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- WriteArrayLength(valueArray.Length);
- for (int i = 0; i < valueArray.Length; i++)
- Serialize(ref valueArray[i], serializeFlags);
- }
- else
- {
- var count = ReadArrayLength();
- valueArray = new T[count];
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- for (int index = 0; index < count; index++)
- Serialize(ref valueArray[index], serializeFlags);
- }
- }
- /// <summary>
- /// Serializes an array of static values that are implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="valueArray">An array of value to serialize</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void SerializeWithNoInstance<T>(ref T[] valueArray, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- WriteArrayLength(valueArray.Length);
- for (int i = 0; i < valueArray.Length; i++)
- SerializeWithNoInstance(ref valueArray[i], serializeFlags);
- }
- else
- {
- var count = ReadArrayLength();
- valueArray = new T[count];
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- for (int index = 0; index < count; index++)
- SerializeWithNoInstance(ref valueArray[index], serializeFlags);
- }
- }
- /// <summary>
- /// Serializes count elements in an array of static values that are implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="valueArray">An array of value to serialize</param>
- /// <param name="count">Count elements to serialize. See remarks.</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
- /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
- /// when we want to serialize the count of an array separately from the array.
- /// </remarks>
- public void Serialize<T>(ref T[] valueArray, int count, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- for (int i = 0; i < count; i++)
- Serialize(ref valueArray[i], serializeFlags);
- }
- else
- {
- valueArray = new T[count];
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- for (int index = 0; index < count; index++)
- Serialize(ref valueArray[index], serializeFlags);
- }
- }
- /// <summary>
- /// Serializes an array of bytes.
- /// </summary>
- /// <param name="valueArray">An array of bytes to serialize</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void Serialize(ref byte[] valueArray, SerializeFlags serializeFlags = SerializeFlags.Normal)
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
-
- WriteArrayLength(valueArray.Length);
- Writer.Write(valueArray);
- }
- else
- {
- int count = ReadArrayLength();
- valueArray = new byte[count];
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- Reader.Read(valueArray, 0, count);
- }
- }
- /// <summary>
- /// Serializes an array of bytes.
- /// </summary>
- /// <param name="valueArray">An array of bytes to serialize</param>
- /// <param name="count">Count elements to serialize. See remarks.</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
- /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
- /// when we want to serialize the count of an array separately from the array.
- /// </remarks>
- public void Serialize(ref byte[] valueArray, int count, SerializeFlags serializeFlags = SerializeFlags.Normal)
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueArray, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- Writer.Write(valueArray, 0, count);
- }
- else
- {
- valueArray = new byte[count];
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueArray, storeObjectRef);
- Reader.Read(valueArray, 0, count);
- }
- }
- /// <summary>
- /// Serializes a list of static values that are implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="valueList">A list of value to serialize</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void Serialize<T>(ref List<T> valueList, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueList, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
-
- WriteArrayLength(valueList.Count);
- foreach (var value in valueList)
- {
- T localValue = value;
- Serialize(ref localValue);
- }
- }
- else
- {
- var count = ReadArrayLength();
- valueList = new List<T>(count);
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
- for (int index = 0; index < count; index++)
- {
- var value = default(T);
- Serialize(ref value);
- valueList.Add(value);
- }
- }
- }
- /// <summary>
- /// Serializes a list of static values that are implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="valueList">A list of value to serialize</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void SerializeThis<T>(List<T> valueList, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
- {
- if (Mode == SerializerMode.Write)
- {
- WriteArrayLength(valueList.Count);
- foreach (var value in valueList)
- {
- T localValue = value;
- Serialize(ref localValue);
- }
- }
- else
- {
- var count = ReadArrayLength();
- for (int index = 0; index < count; index++)
- {
- var value = default(T);
- Serialize(ref value);
- valueList.Add(value);
- }
- }
- }
- /// <summary>
- /// Serializes a list of primitive values using a specific serializer method from this instance.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="valueList">A list of value to serialize</param>
- /// <param name="serializerMethod">A method of this instance to serialize the primitive T type</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void Serialize<T>(ref List<T> valueList, SerializerPrimitiveAction<T> serializerMethod, SerializeFlags serializeFlags = SerializeFlags.Normal)
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueList, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
- WriteArrayLength(valueList.Count);
- foreach (var value in valueList)
- {
- T localValue = value;
- serializerMethod(ref localValue);
- }
- }
- else
- {
- var count = ReadArrayLength();
- EnsureList(ref valueList, count);
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
- for (int i = 0; i < count; i++)
- {
- var localValue = default(T);
- serializerMethod(ref localValue);
- valueList.Add(localValue);
- }
- }
- }
- /// <summary>
- /// Serializes count elements from a list of static values that are implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="valueList">A list of value to serialize</param>
- /// <param name="count">Count elements to serialize. See remarks.</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
- /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
- /// when we want to serialize the count of an array separately from the array.
- /// </remarks>
- public void Serialize<T>(ref List<T> valueList, int count, SerializeFlags serializeFlags = SerializeFlags.Normal) where T : IDataSerializable, new()
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueList, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
- for (int i = 0; i < count; i++)
- {
- T localValue = valueList[i];
- Serialize(ref localValue, serializeFlags);
- }
- }
- else
- {
- EnsureList(ref valueList, count);
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
- for (int index = 0; index < count; index++)
- {
- var value = default(T);
- Serialize(ref value, serializeFlags);
- valueList.Add(value);
- }
- }
- }
- /// <summary>
- /// Serializes count elements from a list of primitive values using a specific serializer method from this instance.
- /// </summary>
- /// <typeparam name="T">Type of the data to serialize.</typeparam>
- /// <param name="valueList">A list of value to serialize</param>
- /// <param name="serializerMethod">A method of this instance to serialize the primitive T type</param>
- /// <param name="count">Count elements to serialize. See remarks.</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.<br/>
- /// <strong>Caution</strong>: Also unlike the plain array version, the count is not serialized. This method is useful
- /// when we want to serialize the count of an array separately from the array.
- /// </remarks>
- public void Serialize<T>(ref List<T> valueList, int count, SerializerPrimitiveAction<T> serializerMethod, SerializeFlags serializeFlags = SerializeFlags.Normal)
- {
- int storeObjectRef;
- if (SerializeIsNull(ref valueList, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
- for (int i = 0; i < count; i++)
- {
- T localValue = valueList[i];
- serializerMethod(ref localValue);
- }
- }
- else
- {
- EnsureList(ref valueList, count);
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(valueList, storeObjectRef);
- for (int i = 0; i < count; i++)
- {
- var localValue = default(T);
- serializerMethod(ref localValue);
- valueList.Add(localValue);
- }
- }
- }
- private void EnsureList<T>(ref List<T> valueList, int count)
- {
- // If there is a list provided, use it in place instead of allocating a new one
- if (valueList != null)
- {
- valueList.Clear();
- if (valueList.Capacity < count)
- {
- valueList.Capacity = count;
- }
- }
- else
- {
- valueList = new List<T>(count);
- }
- }
- /// <summary>
- /// Serializes a dictionary of key/values that are both implementing the <see cref="IDataSerializable"/> interface.
- /// </summary>
- /// <typeparam name="TKey">Type of key to serialize.</typeparam>
- /// <typeparam name="TValue">Type of value to serialize.</typeparam>
- /// <param name="dictionary">A dictionary to serialize</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void Serialize<TKey, TValue>(ref Dictionary<TKey, TValue> dictionary, SerializeFlags serializeFlags = SerializeFlags.Normal)
- where TKey : IDataSerializable, new()
- where TValue : IDataSerializable, new()
- {
- int storeObjectRef;
- if (SerializeIsNull(ref dictionary, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(dictionary, storeObjectRef);
-
- WriteArrayLength(dictionary.Count);
- foreach (var value in dictionary)
- {
- TKey localKey = value.Key;
- TValue localValue = value.Value;
- localKey.Serialize(this);
- localValue.Serialize(this);
- }
- }
- else
- {
- var count = ReadArrayLength();
- dictionary = new Dictionary<TKey, TValue>(count);
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(dictionary, storeObjectRef);
- for (int i = 0; i < count; i++)
- {
- TKey localKey = default(TKey);
- TValue localValue = default(TValue);
- localKey.Serialize(this);
- localValue.Serialize(this);
- dictionary.Add(localKey, localValue);
- }
- }
- }
- /// <summary>
- /// Serializes a dictionary of key/values.
- /// </summary>
- /// <typeparam name="TKey">Type of key to serialize that is implementing the <see cref="IDataSerializable"/> interface.</typeparam>
- /// <typeparam name="TValue">Type of primitive value with its associated serializer.</typeparam>
- /// <param name="dictionary">A dictionary to serialize</param>
- /// <param name="valueSerializer">Serializer used for the TValue.</param>
- /// <param name="serializeFlags">Type of serialization, see <see cref="SerializeFlags"/>.</param>
- /// <remarks>
- /// Note that depending on the serialization <see cref="Mode"/>, this method reads or writes the value.
- /// </remarks>
- public void Serialize<TKey, TValue>(ref Dictionary<TKey, TValue> dictionary, SerializerPrimitiveAction<TValue> valueSerializer, SerializeFlags serializeFlags = SerializeFlags.Normal) where TKey : IDataSerializable, new()
- {
- int storeObjectRef;
- if (SerializeIsNull(ref dictionary, out storeObjectRef, serializeFlags))
- return;
- if (Mode == SerializerMode.Write)
- {
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(dictionary, storeObjectRef);
- WriteArrayLength(dictionary.Count);
- foreach (var value in dictionary)
- {
- TKey localKey = value.Key;
- TValue localValue = value.Value;
- localKey.Serialize(this);
- valueSerializer(ref localValue);
- }
- }
- else
- {
- var count = ReadArrayLength();
- dictionary = new Dictionary<TKey, TValue>(count);
-
- // Store ObjectRef
- if (storeObjectRef >= 0) StoreObjectRef(dictionary, storeObjectRef);
- for (int i = 0; i < count; i++)
- {
- TKey localKey = default(TKey);
- TValue localValue = default(TValue);
- localKey.Serialize(this);
- valueSerializer(ref localValue);
- …
Large files files are truncated, but you can click here to view the full file