/// <summary> /// Reads a <see cref="System.Decimal"/> value. /// </summary> /// <param name="stream">Stream to read the value from.</param> /// <returns>The read value.</returns> internal decimal ReadPrimitive_Decimal(Stream stream) { const int elementSize = sizeof(decimal); int bytesRead = stream.Read(TempBuffer_Buffer, 0, elementSize); if (bytesRead < elementSize) { throw new SerializationException("Unexpected end of stream."); } #if NETSTANDARD2_0 || NETSTANDARD2_1 || NET461 Buffer.BlockCopy(TempBuffer_Buffer, 0, TempBuffer_Int32, 0, elementSize); if (mDeserializingLittleEndian != BitConverter.IsLittleEndian) { EndiannessHelper.SwapBytes(ref TempBuffer_Int32[0]); EndiannessHelper.SwapBytes(ref TempBuffer_Int32[1]); EndiannessHelper.SwapBytes(ref TempBuffer_Int32[2]); EndiannessHelper.SwapBytes(ref TempBuffer_Int32[3]); } return(new decimal(TempBuffer_Int32)); #elif NET5_0_OR_GREATER var intBuffer = MemoryMarshal.Cast <byte, int>(TempBuffer_Buffer.AsSpan(0, elementSize)); if (mDeserializingLittleEndian != BitConverter.IsLittleEndian) { EndiannessHelper.SwapBytes(ref intBuffer[0]); EndiannessHelper.SwapBytes(ref intBuffer[1]); EndiannessHelper.SwapBytes(ref intBuffer[2]); EndiannessHelper.SwapBytes(ref intBuffer[3]); } return(new decimal(intBuffer)); #else #error Unhandled .NET framework #endif }
/// <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> /// Reads a <see cref="System.DateTimeOffset"/> object. /// </summary> /// <param name="stream">Stream to read the DateTimeOffset object from.</param> /// <returns>The read <see cref="System.DateTimeOffset"/> object.</returns> internal DateTimeOffset ReadPrimitive_DateTimeOffset(Stream stream) { const int elementSize = 2 * sizeof(long); int bytesRead = stream.Read(TempBuffer_Buffer, 0, elementSize); if (bytesRead < elementSize) { throw new SerializationException("Unexpected end of stream."); } long dateTimeTicks = MemoryMarshal.Read <long>(TempBuffer_Buffer); long timezoneOffsetTicks = MemoryMarshal.Read <long>(TempBuffer_Buffer.AsSpan().Slice(8)); if (mDeserializingLittleEndian != BitConverter.IsLittleEndian) { EndiannessHelper.SwapBytes(ref dateTimeTicks); EndiannessHelper.SwapBytes(ref timezoneOffsetTicks); } return(new DateTimeOffset(dateTimeTicks, new TimeSpan(timezoneOffsetTicks))); }
/// <summary> /// Writes a <see cref="System.Decimal"/> value. /// </summary> /// <param name="value">Value to write.</param> /// <param name="writer">Buffer writer to write the value to.</param> internal void WritePrimitive_Decimal(decimal value, IBufferWriter <byte> writer) { const int elementSize = sizeof(decimal); var buffer = writer.GetSpan(1 + elementSize); buffer[0] = (byte)PayloadType.Decimal; #if NETSTANDARD2_0 || NETSTANDARD2_1 || NET461 int[] bits = decimal.GetBits(value); Buffer.BlockCopy(bits, 0, TempBuffer_Buffer, 0, elementSize); TempBuffer_Buffer.AsSpan(0, elementSize).CopyTo(buffer.Slice(1)); #elif NET5_0_OR_GREATER Span <int> temp = stackalloc int[4]; decimal.TryGetBits(value, temp, out int valuesWritten); Debug.Assert(valuesWritten * sizeof(int) == elementSize); MemoryMarshal.Cast <int, byte>(temp).CopyTo(buffer.Slice(1)); #else #error Unhandled .NET framework #endif writer.Advance(1 + elementSize); }
/// <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 a <see cref="System.Guid"/> object. /// </summary> /// <param name="stream">Stream to read the Guid object from.</param> /// <returns>The read <see cref="System.Guid"/> object.</returns> internal Guid ReadPrimitive_Guid(Stream stream) { const int elementSize = 16; #if NETSTANDARD2_0 || NET461 byte[] buffer = new byte[elementSize]; int bytesRead = stream.Read(buffer, 0, elementSize); if (bytesRead < elementSize) { throw new SerializationException("Unexpected end of stream."); } return(new Guid(buffer)); #elif NETSTANDARD2_1 || NET5_0_OR_GREATER int bytesRead = stream.Read(TempBuffer_Buffer, 0, elementSize); if (bytesRead < elementSize) { throw new SerializationException("Unexpected end of stream."); } return(new Guid(TempBuffer_Buffer.AsSpan(0, 16))); #else #error Unhandled .NET framework #endif }