/// <summary> /// Writes the contents of a stream to the archive (from the current position up to the end of the stream). /// </summary> /// <param name="s">Stream to write.</param> public void Write(Stream s) { // write payload type var buffer = mBufferWriter.GetSpan(1); buffer[0] = (byte)PayloadType.Buffer; mBufferWriter.Advance(1); // write data chunkwise while (true) { // read a chunk of data int maxBytesToRead = Serializer.MaxChunkSize - Leb128EncodingHelper.MaxBytesFor32BitValue; mSerializer.EnsureTemporaryByteBufferSize(maxBytesToRead); int bytesRead = s.Read(mSerializer.TempBuffer_Buffer, 0, maxBytesToRead); if (bytesRead == 0) { break; } // write the chunk into the archive buffer = mBufferWriter.GetSpan(Leb128EncodingHelper.MaxBytesFor32BitValue + bytesRead); int bufferIndex = Leb128EncodingHelper.Write(buffer, bytesRead); mSerializer.TempBuffer_Buffer.AsSpan().Slice(0, bytesRead).CopyTo(buffer.Slice(bufferIndex)); bufferIndex += bytesRead; mBufferWriter.Advance(bufferIndex); } }
/// <summary> /// Reads an array of <see cref="System.Decimal"/> from a stream (for arrays with zero-based indexing). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <returns>The read array.</returns> private decimal[] ReadArrayOfDecimal(Stream stream) { // read array length int length = Leb128EncodingHelper.ReadInt32(stream); int size = 16 * length; // read data from stream if (mTempBuffer_BigBuffer.Length < length) { mTempBuffer_BigBuffer = new byte[size]; } stream.Read(mTempBuffer_BigBuffer, 0, size); // read array data decimal[] array = new decimal[length]; int index = 0; for (int i = 0; i < length; i++) { Buffer.BlockCopy(mTempBuffer_BigBuffer, index, mTempBuffer_Int32, 0, 16); array[i] = new decimal(mTempBuffer_Int32); index += 16; } mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Writes an array of <see cref="System.String"/> values (for arrays with zero-based indexing). /// </summary> /// <param name="array">Array to write.</param> /// <param name="stream">Stream to write the array to.</param> private void WriteArrayOfString(string[] array, Stream stream) { // write type and array length mTempBuffer_Buffer[0] = (byte)PayloadType.ArrayOfString; int count = Leb128EncodingHelper.Write(mTempBuffer_Buffer, 1, array.Length); stream.Write(mTempBuffer_Buffer, 0, 1 + count); // write array data for (int i = 0; i < array.Length; i++) { string s = array[i]; uint id; if (s == null) { stream.WriteByte((byte)PayloadType.NullReference); } else if (mSerializedObjectIdTable.TryGetValue(s, out id)) { SerializeObjectId(stream, id); } else { WritePrimitive_String(s, stream); } } mSerializedObjectIdTable.Add(array, mNextSerializedObjectId++); }
/// <summary> /// Writes an array of <see cref="System.Decimal"/> (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="array">Array to write.</param> /// <param name="stream">Stream to write the array to.</param> private void WriteMultidimensionalArrayOfDecimal(Array array, Stream stream) { //int totalCount = 1; stream.WriteByte((byte)PayloadType.MultidimensionalArrayOfDecimal); // payload type Leb128EncodingHelper.Write(stream, array.Rank); // number of dimensions int[] indices = new int[array.Rank]; for (int i = 0; i < array.Rank; i++) { // ...dimension information... indices[i] = array.GetLowerBound(i); Leb128EncodingHelper.Write(stream, indices[i]); // lower bound of the dimension int count = array.GetLength(i); Leb128EncodingHelper.Write(stream, count); // number of elements in the dimension //totalCount *= count; } // write array elements for (int i = 0; i < array.Length; i++) { decimal value = (decimal)array.GetValue(indices); int[] bits = decimal.GetBits(value); Buffer.BlockCopy(bits, 0, mTempBuffer_Buffer, 0, 16); stream.Write(mTempBuffer_Buffer, 0, 16); IncrementArrayIndices(indices, array); } mSerializedObjectIdTable.Add(array, mNextSerializedObjectId++); }
/// <summary> /// Reads an array of primitive value types (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <param name="type">Type of an array element.</param> /// <param name="elementSize">Size of an array element.</param> /// <returns>The read array.</returns> private Array ReadMultidimensionalArrayOfPrimitives(Stream stream, Type type, int elementSize) { // read header int totalCount = 1; int ranks = Leb128EncodingHelper.ReadInt32(stream); int[] lowerBounds = new int[ranks]; int[] lengths = new int[ranks]; for (int i = 0; i < ranks; i++) { lowerBounds[i] = Leb128EncodingHelper.ReadInt32(stream); lengths[i] = Leb128EncodingHelper.ReadInt32(stream); totalCount *= lengths[i]; } // create an array of the specified type Array array = Array.CreateInstance(type, lengths, lowerBounds); // read array data int size = totalCount * elementSize; if (mTempBuffer_BigBuffer.Length < size) { mTempBuffer_BigBuffer = new byte[size]; } stream.Read(mTempBuffer_BigBuffer, 0, size); Buffer.BlockCopy(mTempBuffer_BigBuffer, 0, array, 0, size); mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Reads an array of <see cref="System.String"/> from a stream (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <returns>The read array.</returns> private Array ReadMultidimensionalStringArray(Stream stream) { // read header int totalCount = 1; int ranks = Leb128EncodingHelper.ReadInt32(stream); int[] lowerBounds = new int[ranks]; int[] lengths = new int[ranks]; int[] indices = new int[ranks]; for (int i = 0; i < ranks; i++) { lowerBounds[i] = Leb128EncodingHelper.ReadInt32(stream); lengths[i] = Leb128EncodingHelper.ReadInt32(stream); indices[i] = lowerBounds[i]; totalCount *= lengths[i]; } // create an array of strings Array array = Array.CreateInstance(typeof(string), lengths, lowerBounds); // read array elements for (int i = 0; i < array.Length; i++) { object obj = InnerDeserialize(stream, null); array.SetValue(obj, indices); IncrementArrayIndices(indices, array); } mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Writes a <see cref="System.Char"/> value. /// </summary> /// <param name="value">Value to write.</param> /// <param name="stream">Stream to write the value to.</param> internal void WritePrimitive_Char(char value, Stream stream) { mTempBuffer_Buffer[0] = (byte)PayloadType.Char; int count = Leb128EncodingHelper.Write(mTempBuffer_Buffer, 1, (uint)value); stream.Write(mTempBuffer_Buffer, 0, 1 + count); }
/// <summary> /// Reads an array of <see cref="System.Decimal"/> from a stream (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <returns>The read array.</returns> private Array ReadMultidimensionalArrayOfDecimal(Stream stream) { // read header int totalCount = 1; int ranks = Leb128EncodingHelper.ReadInt32(stream); int[] lowerBounds = new int[ranks]; int[] lengths = new int[ranks]; int[] indices = new int[ranks]; for (int i = 0; i < ranks; i++) { lowerBounds[i] = Leb128EncodingHelper.ReadInt32(stream); lengths[i] = Leb128EncodingHelper.ReadInt32(stream); indices[i] = lowerBounds[i]; totalCount *= lengths[i]; } // create an array of decimals Array array = Array.CreateInstance(typeof(decimal), lengths, lowerBounds); // read array elements for (int i = 0; i < array.Length; i++) { stream.Read(mTempBuffer_Buffer, 0, 16); Buffer.BlockCopy(mTempBuffer_Buffer, 0, mTempBuffer_Int32, 0, 16); decimal value = new decimal(mTempBuffer_Int32); array.SetValue(value, indices); IncrementArrayIndices(indices, array); } mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Writes a <see cref="System.UInt64"/> value. /// </summary> /// <param name="value">Value to write.</param> /// <param name="stream">Stream to write the value to.</param> internal void WritePrimitive_UInt64(ulong value, Stream stream) { mTempBuffer_Buffer[0] = (byte)PayloadType.UInt64; int count = Leb128EncodingHelper.Write(mTempBuffer_Buffer, 1, value); stream.Write(mTempBuffer_Buffer, 0, 1 + count); }
/// <summary> /// Reads an array of <see cref="System.DateTime"/> from a stream (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <returns>The read array.</returns> private Array ReadMultidimensionalDateTimeArray(Stream stream) { // read header int totalCount = 1; int ranks = Leb128EncodingHelper.ReadInt32(stream); int[] lowerBounds = new int[ranks]; int[] lengths = new int[ranks]; int[] indices = new int[ranks]; for (int i = 0; i < ranks; i++) { lowerBounds[i] = Leb128EncodingHelper.ReadInt32(stream); lengths[i] = Leb128EncodingHelper.ReadInt32(stream); indices[i] = lowerBounds[i]; totalCount *= lengths[i]; } // create an array of datetimes Array array = Array.CreateInstance(typeof(DateTime), lengths, lowerBounds); // read array elements for (int i = 0; i < array.Length; i++) { stream.Read(mTempBuffer_Buffer, 0, 8); long l = BitConverter.ToInt64(mTempBuffer_Buffer, 0); array.SetValue(DateTime.FromBinary(l), indices); IncrementArrayIndices(indices, array); } mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Writes a <see cref="System.Int16"/> value. /// </summary> /// <param name="value">Value to write.</param> /// <param name="stream">Stream to write the value to.</param> internal void WritePrimitive_Int16(short value, Stream stream) { mTempBuffer_Buffer[0] = (byte)PayloadType.Int16; int count = Leb128EncodingHelper.Write(mTempBuffer_Buffer, 1, value); stream.Write(mTempBuffer_Buffer, 0, 1 + count); }
/// <summary> /// Reads an array of objects (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <param name="context">Context object to pass to an internal/external object serializer class.</param> /// <returns>The read array.</returns> /// <exception cref="SerializationException">Stream ended unexpectedly.</exception> private object ReadMultidimensionalArrayOfObjects(Stream stream, object context) { Type type = mCurrentDeserializedType.Type; // read header int totalCount = 1; int ranks = Leb128EncodingHelper.ReadInt32(stream); int[] lowerBounds = new int[ranks]; int[] lengths = new int[ranks]; int[] indices = new int[ranks]; for (int i = 0; i < ranks; i++) { lowerBounds[i] = Leb128EncodingHelper.ReadInt32(stream); lengths[i] = Leb128EncodingHelper.ReadInt32(stream); indices[i] = lowerBounds[i]; totalCount *= lengths[i]; } // create an array with elements of the specified type Array array = Array.CreateInstance(type, lengths, lowerBounds); // read array elements for (int i = 0; i < array.Length; i++) { object obj = InnerDeserialize(stream, null); array.SetValue(obj, indices); IncrementArrayIndices(indices, array); } mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Writes an array of primitive value types (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="type">Payload type corresponding to the type of the array.</param> /// <param name="array">Array to write.</param> /// <param name="elementSize">Size of an array element.</param> /// <param name="stream">Stream to write the array to.</param> private void WriteMultidimensionalArrayOfPrimitives( PayloadType type, Array array, int elementSize, Stream stream) { int totalCount = 1; stream.WriteByte((byte)type); // payload type Leb128EncodingHelper.Write(stream, array.Rank); // number of dimensions for (int i = 0; i < array.Rank; i++) { // ...dimension information... Leb128EncodingHelper.Write(stream, array.GetLowerBound(i)); // lower bound of the dimension int count = array.GetLength(i); Leb128EncodingHelper.Write(stream, count); // number of elements in the dimension totalCount *= count; } int size = totalCount * elementSize; if (mTempBuffer_BigBuffer.Length < size) { mTempBuffer_BigBuffer = new byte[size]; } Buffer.BlockCopy(array, 0, mTempBuffer_BigBuffer, 0, size); stream.Write(mTempBuffer_BigBuffer, 0, size); mSerializedObjectIdTable.Add(array, mNextSerializedObjectId++); }
/// <summary> /// Prepares an archive for deserializing the base class of a serializable class. /// </summary> /// <param name="context">Context object to pass to the serializer of the base class.</param> /// <returns>Deserialization archive for the base class.</returns> /// <exception cref="ArgumentException">Type does not have a base type or it is not serializable.</exception> /// <exception cref="SerializationException"> /// The serializer version in the archive is greater than the maximum supported version of the base class. /// </exception> public DeserializationArchive PrepareBaseArchive(object context) { var type = DataType.BaseType ?? throw new ArgumentException($"{DataType.FullName} does not have a base type."); // read payload type (expecting a base class archive) ReadAndCheckPayloadType(PayloadType.BaseArchiveStart); // read version number uint deserializedVersion = Leb128EncodingHelper.ReadUInt32(mStream); // check maximum supported version number uint currentVersion = Serializer.GetSerializerVersion(type); // throws ArgumentException if type is not serializable if (deserializedVersion > currentVersion) { // version of the archive that is about to be deserialized is greater than // the version the internal object serializer supports string error = $"Deserializing type '{type.FullName}' failed due to a version conflict (got version: {deserializedVersion}, max. supported version: {currentVersion})."; sLog.Write(LogLevel.Error, error); throw new SerializationException(error); } // version is ok, create archive... return(new DeserializationArchive(mSerializer, mStream, type, deserializedVersion, context)); }
/// <summary> /// Writes an array of <see cref="System.Byte"/> values (for arrays with zero-based indexing). /// </summary> /// <param name="array">Array to write.</param> /// <param name="stream">Stream to write the array to.</param> private void WriteArrayOfByte(byte[] array, Stream stream) { mTempBuffer_Buffer[0] = (byte)PayloadType.ArrayOfByte; int count = Leb128EncodingHelper.Write(mTempBuffer_Buffer, 1, array.Length); stream.Write(mTempBuffer_Buffer, 0, 1 + count); stream.Write(array, 0, array.Length); mSerializedObjectIdTable.Add(array, mNextSerializedObjectId++); }
/// <summary> /// Reads a byte buffer using a stream. /// </summary> /// <returns>Stream containing data to read.</returns> /// <exception cref="SerializationException">Thrown if deserialization fails due to some reason.</exception> public Stream ReadStream() { // read payload type and size of the following buffer ReadAndCheckPayloadType(PayloadType.Buffer); long length = Leb128EncodingHelper.ReadInt64(mStream); mArchiveStream = new SerializerArchiveStream(mStream, length); return(mArchiveStream); }
/// <summary> /// Opens a base archive and calls the serializer of the derived type (for base class serialization). /// </summary> /// <param name="context">Context object to pass to the serializer of the base class.</param> /// <exception cref="ArgumentException">Specified type is not serializable.</exception> public void WriteBaseArchive(object context = null) { var baseClassType = DataType.BaseType ?? throw new ArgumentException($"{DataType.FullName} does not have a base class."); // try internal object serializer var ios = Serializer.GetInternalObjectSerializer(mObjectToSerialize, baseClassType, out uint version); if (ios != null) { // consider serializer version overrides... if (mSerializer.GetSerializerVersionOverride(baseClassType, out uint versionOverride)) { version = versionOverride; } // write base archive header var buffer = mBufferWriter.GetSpan(1 + Leb128EncodingHelper.MaxBytesFor32BitValue); int bufferIndex = 0; buffer[bufferIndex++] = (byte)PayloadType.BaseArchiveStart; bufferIndex += Leb128EncodingHelper.Write(buffer.Slice(bufferIndex), version); mBufferWriter.Advance(bufferIndex); // call the Serialize() method of the base class var archive = new SerializationArchive(mSerializer, mBufferWriter, baseClassType, mObjectToSerialize, version, context); var serializeDelegate = Serializer.GetInternalObjectSerializerSerializeCaller(baseClassType); serializeDelegate(ios, archive); return; } // try external object serializer var eos = ExternalObjectSerializerFactory.GetExternalObjectSerializer(baseClassType, out version); if (eos != null) { // consider serializer version overrides... if (mSerializer.GetSerializerVersionOverride(baseClassType, out uint versionOverride)) { version = versionOverride; } // write base archive header var buffer = mBufferWriter.GetSpan(1 + Leb128EncodingHelper.MaxBytesFor32BitValue); int bufferIndex = 0; buffer[bufferIndex++] = (byte)PayloadType.BaseArchiveStart; bufferIndex += Leb128EncodingHelper.Write(buffer.Slice(bufferIndex), version); mBufferWriter.Advance(bufferIndex); // serialize object var archive = new SerializationArchive(mSerializer, mBufferWriter, baseClassType, mObjectToSerialize, version, context); eos.Serialize(archive, mObjectToSerialize); return; } // specified type is not serializable... throw new ArgumentException($"Specified type ({baseClassType.FullName}) is not serializable.", nameof(baseClassType)); }
/// <summary> /// Reads an array of <see cref="System.Byte"/> from a stream (for arrays with zero-based indexing). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <returns>The read array.</returns> private byte[] ReadArrayOfByte(Stream stream) { // read array length int length = Leb128EncodingHelper.ReadInt32(stream); // read array data byte[] array = new byte[length]; stream.Read(array, 0, length); mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Writes a multidimensional array of <see cref="System.String"/> to a stream (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="array">Array to serialize.</param> /// <param name="stream">Stream to serialize the array to.</param> private void WriteMultidimensionalArrayOfString(Array array, Stream stream) { int totalCount = 1; stream.WriteByte((byte)PayloadType.MultidimensionalArrayOfString); // payload type Leb128EncodingHelper.Write(stream, array.Rank); // number of dimensions for (int i = 0; i < array.Rank; i++) { // ...dimension information... Leb128EncodingHelper.Write(stream, array.GetLowerBound(i)); // lower bound of the dimension int count = array.GetLength(i); Leb128EncodingHelper.Write(stream, count); // number of elements in the dimension totalCount *= count; } // prepare indexing array int[] indices = new int[array.Rank]; for (int i = 0; i < array.Rank; i++) { indices[i] = array.GetLowerBound(i); } // write array elements for (int i = 0; i < array.Length; i++) { string s = (string)array.GetValue(indices); if (s != null) { uint id; if (mSerializedObjectIdTable.TryGetValue(s, out id)) { SerializeObjectId(stream, id); } else { WritePrimitive_String(s, stream); } } else { stream.WriteByte((byte)PayloadType.NullReference); } IncrementArrayIndices(indices, array); } mSerializedObjectIdTable.Add(array, mNextSerializedObjectId++); }
/// <summary> /// Reads an array of <see cref="System.String"/> from a stream (for arrays with zero-based indexing). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <returns>The read array.</returns> private string[] ReadStringArray(Stream stream) { // read array length int length = Leb128EncodingHelper.ReadInt32(stream); // read array data string[] array = new string[length]; for (int i = 0; i < length; i++) { object obj = InnerDeserialize(stream, null); array[i] = (string)obj; } mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Reads a <see cref="System.String"/> object. /// </summary> /// <param name="stream">Stream to read the string object from.</param> /// <returns>The read string.</returns> internal string ReadPrimitive_String(Stream stream) { int size = Leb128EncodingHelper.ReadInt32(stream); // read encoded string if (mTempBuffer_BigBuffer.Length < size) { mTempBuffer_BigBuffer = new byte[size]; } stream.Read(mTempBuffer_BigBuffer, 0, size); // decode string string s = Encoding.UTF8.GetString(mTempBuffer_BigBuffer, 0, size); mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, s); return(s); }
/// <summary> /// Prepares a buffer for array serialization /// (inits payload type, the length field and reserves space for the value) /// </summary> /// <param name="type">Type of the payload.</param> /// <param name="length">Length of the array (in elements).</param> /// <param name="elementSize">Size of an element (in bytes).</param> /// <param name="size">Receives the number of valid bytes in <see cref="mTempBuffer_BigBuffer"/>.</param> /// <returns>Index in the returned buffer where the array data part begins.</returns> private int PrepareArrayBuffer( PayloadType type, int length, int elementSize, out int size) { int sizeByteCount = Leb128EncodingHelper.GetByteCount(length); size = 1 + sizeByteCount + length * elementSize; if (mTempBuffer_BigBuffer.Length < size) { mTempBuffer_BigBuffer = new byte[size]; } mTempBuffer_BigBuffer[0] = (byte)type; Leb128EncodingHelper.Write(mTempBuffer_BigBuffer, 1, length); return(1 + sizeByteCount); }
/// <summary> /// Writes a <see cref="System.UInt64"/> value. /// </summary> /// <param name="value">Value to write.</param> /// <param name="writer">Buffer writer to write the value to.</param> internal void WritePrimitive_UInt64(ulong value, IBufferWriter <byte> writer) { if (SerializationOptimization == SerializationOptimization.Speed || !IsLeb128EncodingMoreEfficient(value)) { // use native encoding var buffer = writer.GetSpan(9); buffer[0] = (byte)PayloadType.UInt64_Native; MemoryMarshal.Write(buffer.Slice(1), ref value); writer.Advance(9); } else { // use LEB128 encoding var buffer = writer.GetSpan(1 + Leb128EncodingHelper.MaxBytesFor64BitValue); buffer[0] = (byte)PayloadType.UInt64_LEB128; int count = Leb128EncodingHelper.Write(buffer.Slice(1), value); writer.Advance(1 + count); } }
/// <summary> /// Writes an array of objects (for arrays with zero-based indexing). /// </summary> /// <param name="array">Array to write.</param> /// <param name="stream">Stream to write the array to.</param> private void WriteArrayOfObjects(Array array, Stream stream) { // write type metadata WriteTypeMetadata(stream, array.GetType().GetElementType()); // write type and array length mTempBuffer_Buffer[0] = (byte)PayloadType.ArrayOfObjects; int count = Leb128EncodingHelper.Write(mTempBuffer_Buffer, 1, array.Length); stream.Write(mTempBuffer_Buffer, 0, 1 + count); // write array data for (int i = 0; i < array.Length; i++) { InnerSerialize(stream, array.GetValue(i), null); } mSerializedObjectIdTable.Add(array, mNextSerializedObjectId++); }
/// <summary> /// Reads an array of primitive value types (for arrays with zero-based indexing). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <param name="type">Type of an array element.</param> /// <param name="elementSize">Size of an array element.</param> /// <returns>The read array.</returns> private Array ReadArrayOfPrimitives(Stream stream, Type type, int elementSize) { // read array length int length = Leb128EncodingHelper.ReadInt32(stream); int size = length * elementSize; // read array data Array array = FastActivator.CreateArray(type, length); if (mTempBuffer_BigBuffer.Length < length) { mTempBuffer_BigBuffer = new byte[size]; } stream.Read(mTempBuffer_BigBuffer, 0, size); Buffer.BlockCopy(mTempBuffer_BigBuffer, 0, array, 0, size); mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Writes a <see cref="System.String"/> object. /// </summary> /// <param name="value">String to write.</param> /// <param name="writer">Buffer writer to write the string to.</param> internal void WritePrimitive_String(string value, IBufferWriter <byte> writer) { if (SerializationOptimization == SerializationOptimization.Speed) { // use UTF-16 encoding // => .NET strings are always UTF-16 encoded itself, so no further encoding steps are needed... // write the encoded string int valueByteCount = value.Length * sizeof(char); int maxSize = 1 + Leb128EncodingHelper.MaxBytesFor32BitValue + valueByteCount; var buffer = writer.GetSpan(maxSize); int bufferIndex = 0; buffer[bufferIndex++] = (byte)PayloadType.String_UTF16; bufferIndex += Leb128EncodingHelper.Write(buffer.Slice(bufferIndex), value.Length); MemoryMarshal.AsBytes(value.AsSpan()).CopyTo(buffer.Slice(bufferIndex)); bufferIndex += valueByteCount; writer.Advance(bufferIndex); } else { // use UTF-8 encoding // resize temporary buffer for the encoding the string int size = sUtf8Encoding.GetMaxByteCount(value.Length); EnsureTemporaryByteBufferSize(size); // encode the string int valueByteCount = sUtf8Encoding.GetBytes(value, 0, value.Length, TempBuffer_Buffer, 0); // write the encoded string int maxSize = 1 + Leb128EncodingHelper.MaxBytesFor32BitValue + valueByteCount; var buffer = writer.GetSpan(maxSize); int bufferIndex = 0; buffer[bufferIndex++] = (byte)PayloadType.String_UTF8; bufferIndex += Leb128EncodingHelper.Write(buffer.Slice(1), valueByteCount); TempBuffer_Buffer.AsSpan().Slice(0, valueByteCount).CopyTo(buffer.Slice(bufferIndex)); bufferIndex += valueByteCount; writer.Advance(bufferIndex); } // assign an object id to the serialized string mSerializedObjectIdTable.Add(value, mNextSerializedObjectId++); }
/// <summary> /// Writes a multidimensional array of <see cref="System.DateTime"/> to a stream (for arrays with non-zero-based indexing and/or multiple dimensions). /// </summary> /// <param name="array">Array to serialize.</param> /// <param name="stream">Stream to serialize the array to.</param> private void WriteMultidimensionalArrayOfDateTime(Array array, Stream stream) { int totalCount = 1; stream.WriteByte((byte)PayloadType.MultidimensionalArrayOfDateTime); // payload type Leb128EncodingHelper.Write(stream, array.Rank); // number of dimensions for (int i = 0; i < array.Rank; i++) { // ...dimension information... Leb128EncodingHelper.Write(stream, array.GetLowerBound(i)); // lower bound of the dimension int count = array.GetLength(i); Leb128EncodingHelper.Write(stream, count); // number of elements in the dimension totalCount *= count; } // prepare indexing array int[] indices = new int[array.Rank]; for (int i = 0; i < array.Rank; i++) { indices[i] = array.GetLowerBound(i); } // resize temporary buffer, if necessary int size = 8 * totalCount; if (mTempBuffer_BigBuffer.Length < size) { mTempBuffer_BigBuffer = new byte[size]; } // convert array elements for (int i = 0; i < array.Length; i++) { DateTime dt = (DateTime)array.GetValue(indices); mTempBuffer_Int64[0] = dt.ToBinary(); Buffer.BlockCopy(mTempBuffer_Int64, 0, mTempBuffer_BigBuffer, 8 * i, 8); IncrementArrayIndices(indices, array); } // write to stream stream.Write(mTempBuffer_BigBuffer, 0, size); mSerializedObjectIdTable.Add(array, mNextSerializedObjectId++); }
/// <summary> /// Reads an array of objects (for arrays with zero-based indexing). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <param name="context">Context object to pass to an internal/external object serializer class.</param> /// <returns>The read array.</returns> /// <exception cref="SerializationException">Stream ended unexpectedly.</exception> private object ReadArrayOfObjects(Stream stream, object context) { // assembly and type metadata has been read already Type t = mCurrentDeserializedType.Type; // read array length int length = Leb128EncodingHelper.ReadInt32(stream); // read array elements Array array = FastActivator.CreateArray(t, length); for (int i = 0; i < length; i++) { array.SetValue(InnerDeserialize(stream, context), i); } mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }
/// <summary> /// Reads a <see cref="System.String"/> object (UTF-16 encoding). /// </summary> /// <param name="stream">Stream to read the string object from.</param> /// <returns>The read string.</returns> internal unsafe string ReadPrimitive_String_UTF16(Stream stream) { // read the number of UTF-16 code units int codeUnitCount = Leb128EncodingHelper.ReadInt32(stream); int size = codeUnitCount * sizeof(char); // read encoded string EnsureTemporaryByteBufferSize(size); int bytesRead = stream.Read(TempBuffer_Buffer, 0, size); if (bytesRead < size) { throw new SerializationException("Unexpected end of stream."); } // swap bytes to fix endianness issues, if necessary var buffer = MemoryMarshal.Cast <byte, char>(TempBuffer_Buffer.AsSpan(0, bytesRead)); if (mDeserializingLittleEndian != BitConverter.IsLittleEndian) { for (int i = 0; i < buffer.Length; i++) { EndiannessHelper.SwapBytes(ref buffer[i]); } } // create a string from the buffer #if NETSTANDARD2_0 || NET461 string s; fixed(char *p = buffer) { s = new string(p, 0, buffer.Length); } #elif NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER string s = new string(buffer); #else #error Unhandled .NET framework #endif mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, s); return(s); }
/// <summary> /// Reads an array of <see cref="System.DateTime"/> from a stream (for arrays with zero-based indexing). /// </summary> /// <param name="stream">Stream to read the array from.</param> /// <returns>The read array.</returns> private DateTime[] ReadDateTimeArray(Stream stream) { // read array length int length = Leb128EncodingHelper.ReadInt32(stream); int size = 8 * length; // read array data DateTime[] array = new DateTime[length]; if (mTempBuffer_BigBuffer.Length < size) { mTempBuffer_BigBuffer = new byte[size]; } stream.Read(mTempBuffer_BigBuffer, 0, size); for (int i = 0; i < length; i++) { array[i] = DateTime.FromBinary(BitConverter.ToInt64(mTempBuffer_BigBuffer, 8 * i)); } mDeserializedObjectIdTable.Add(mNextDeserializedObjectId++, array); return(array); }