/// <summary> /// Writes a <see cref="double"/> value to an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to write to.</param> /// <param name="position">The position in the array where the value should be written.</param> /// <param name="value">The value to write.</param> /// <param name="endianness">The endianness.</param> public static void WriteDouble(this byte[] bytes, int position, double value, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfDouble); // this is essentially an unsafe *((long*)&value) var unsigned = (ulong)BitConverter.DoubleToInt64Bits(value); unchecked { if (endianness.IsBigEndian()) { bytes[position] = (byte)(unsigned >> 56); bytes[position + 1] = (byte)(unsigned >> 48); bytes[position + 2] = (byte)(unsigned >> 40); bytes[position + 3] = (byte)(unsigned >> 32); bytes[position + 4] = (byte)(unsigned >> 24); bytes[position + 5] = (byte)(unsigned >> 16); bytes[position + 6] = (byte)(unsigned >> 8); bytes[position + 7] = (byte)unsigned; } else { bytes[position] = (byte)unsigned; bytes[position + 1] = (byte)(unsigned >> 8); bytes[position + 2] = (byte)(unsigned >> 16); bytes[position + 3] = (byte)(unsigned >> 24); bytes[position + 4] = (byte)(unsigned >> 32); bytes[position + 5] = (byte)(unsigned >> 40); bytes[position + 6] = (byte)(unsigned >> 48); bytes[position + 7] = (byte)(unsigned >> 56); } } }
/// <summary> /// Writes a <see cref="float"/> value to an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to write to.</param> /// <param name="position">The position in the array where the value should be written.</param> /// <param name="value">The value to write.</param> /// <param name="endianness">The endianness.</param> public static void WriteFloat(this byte[] bytes, int position, float value, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfFloat); #if NETSTANDARD2_0 var unsigned = (uint)BitConverter.ToInt32(BitConverter.GetBytes(value), 0); #else // this is essentially an unsafe *((int*)&value) var unsigned = (uint)BitConverter.SingleToInt32Bits(value); #endif unchecked { if (endianness.IsBigEndian()) { bytes[position] = (byte)(unsigned >> 24); bytes[position + 1] = (byte)(unsigned >> 16); bytes[position + 2] = (byte)(unsigned >> 8); bytes[position + 3] = (byte)unsigned; } else { bytes[position] = (byte)unsigned; bytes[position + 1] = (byte)(unsigned >> 8); bytes[position + 2] = (byte)(unsigned >> 16); bytes[position + 3] = (byte)(unsigned >> 24); } } }
/// <summary> /// Writes a <see cref="long"/> value to an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to write to.</param> /// <param name="position">The position in the array where the value should be written.</param> /// <param name="value">The value to write.</param> /// <param name="endianness">The endianness.</param> public static void WriteLong(this byte[] bytes, int position, long value, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfLong); var unsigned = (ulong)value; unchecked { if (endianness.IsBigEndian()) { bytes[position] = (byte)(unsigned >> 56); bytes[position + 1] = (byte)(unsigned >> 48); bytes[position + 2] = (byte)(unsigned >> 40); bytes[position + 3] = (byte)(unsigned >> 32); bytes[position + 4] = (byte)(unsigned >> 24); bytes[position + 5] = (byte)(unsigned >> 16); bytes[position + 6] = (byte)(unsigned >> 8); bytes[position + 7] = (byte)unsigned; } else { bytes[position] = (byte)unsigned; bytes[position + 1] = (byte)(unsigned >> 8); bytes[position + 2] = (byte)(unsigned >> 16); bytes[position + 3] = (byte)(unsigned >> 24); bytes[position + 4] = (byte)(unsigned >> 32); bytes[position + 5] = (byte)(unsigned >> 40); bytes[position + 6] = (byte)(unsigned >> 48); bytes[position + 7] = (byte)(unsigned >> 56); } } }
/// <summary> /// Reads a <see cref="char"/> value from an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to read from.</param> /// <param name="position">The position in the array where the value should be read.</param> /// <param name="endianness">The endianness.</param> /// <returns>The value.</returns> public static char ReadChar(this byte[] bytes, int position, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfChar); unchecked { return((char)(endianness.IsBigEndian() ? bytes[position] << 8 | bytes[position + 1] : bytes[position] | bytes[position + 1] << 8)); } }
/// <summary> /// Reads an <see cref="ushort"/> value from an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to read from.</param> /// <param name="position">The position in the array where the value should be read.</param> /// <param name="endianness">The endianness.</param> /// <returns>The value.</returns> public static ushort ReadUShort(this byte[] bytes, int position, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfUnsignedShort); unchecked { return(endianness.IsBigEndian() ? (ushort)(bytes[position + 0] << 8 | bytes[position + 1]) : (ushort)(bytes[position] | bytes[position + 1] << 8)); } }
/// <summary> /// Reads an <see cref="int"/> value from a span of bytes. /// </summary> /// <param name="bytes">The span of bytes to read from.</param> /// <param name="endianness">The endianness.</param> /// <returns>The value.</returns> public static int ReadInt(this ReadOnlySpan <byte> bytes, Endianness endianness) { const byte length = sizeof(int); if (bytes.Length < length) { throw new ArgumentException(ExceptionMessages.NotEnoughBytes, nameof(bytes)); } return(endianness.IsBigEndian() ? bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3] : bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24); }
/// <summary> /// Reads an <see cref="int"/> value from an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to read from.</param> /// <param name="position">The position in the array where the value should be read.</param> /// <param name="endianness">The endianness.</param> /// <returns>The value.</returns> public static int ReadInt(this byte[] bytes, int position, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfInt); unchecked { return(endianness.IsBigEndian() ? bytes[position] << 24 | bytes[position + 1] << 16 | bytes[position + 2] << 8 | bytes[position + 3] : bytes[position] | bytes[position + 1] << 8 | bytes[position + 2] << 16 | bytes[position + 3] << 24); } }
/// <summary> /// Writes an <see cref="ushort"/> value to an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to write to.</param> /// <param name="position">The position in the array where the value should be written.</param> /// <param name="value">The value to write.</param> /// <param name="endianness">The endianness.</param> public static void WriteUShort(this byte[] bytes, int position, ushort value, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfUnsignedShort); unchecked { if (endianness.IsBigEndian()) { bytes[position] = (byte)(value >> 8); bytes[position + 1] = (byte)value; } else { bytes[position] = (byte)value; bytes[position + 1] = (byte)(value >> 8); } } }
/// <summary> /// Reads an <see cref="ushort"/> value from a span of bytes. /// </summary> /// <param name="bytes">The span of bytes to read from.</param> /// <param name="endianness">The endianness.</param> /// <returns>The value.</returns> public static ushort ReadUShort(this ReadOnlySpan <byte> bytes, Endianness endianness) { const byte length = sizeof(ushort); if (bytes.Length < length) { throw new ArgumentException(ExceptionMessages.NotEnoughBytes, nameof(bytes)); } unchecked { return((ushort)(endianness.IsBigEndian() ? bytes[0] << 8 | bytes[1] : bytes[0] | bytes[1] << 8)); } }
/// <summary> /// Reads a <see cref="long"/> value from an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to read from.</param> /// <param name="position">The position in the array where the value should be read.</param> /// <param name="endianness">The endianness.</param> /// <returns>The value.</returns> public static long ReadLong(this byte[] bytes, int position, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfLong); unchecked { return(endianness.IsBigEndian() ? (long)bytes[position] << 56 | (long)bytes[position + 1] << 48 | (long)bytes[position + 2] << 40 | (long)bytes[position + 3] << 32 | (long)bytes[position + 4] << 24 | (long)bytes[position + 5] << 16 | (long)bytes[position + 6] << 8 | bytes[position + 7] : bytes[position] | (long)bytes[position + 1] << 8 | (long)bytes[position + 2] << 16 | (long)bytes[position + 3] << 24 | (long)bytes[position + 4] << 32 | (long)bytes[position + 5] << 40 | (long)bytes[position + 6] << 48 | (long)bytes[position + 7] << 56); } }
/// <summary> /// Writes a <see cref="char"/> value to an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to write to.</param> /// <param name="position">The position in the array where the value should be written.</param> /// <param name="value">The value to write.</param> /// <param name="endianness">The endianness.</param> public static void WriteChar(this byte[] bytes, int position, char value, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfChar); var unsigned = value; unchecked { if (endianness.IsBigEndian()) { bytes[position] = (byte)(unsigned >> 8); bytes[position + 1] = (byte)unsigned; } else { bytes[position] = (byte)unsigned; bytes[position + 1] = (byte)(unsigned >> 8); } } }
/// <summary> /// Writes an <see cref="int"/> value to an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to write to.</param> /// <param name="position">The position in the array where the value should be written.</param> /// <param name="value">The value to write.</param> /// <param name="endianness">The endianness.</param> public static void WriteInt(this byte[] bytes, int position, int value, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfInt); var unsigned = (uint)value; unchecked { if (endianness.IsBigEndian()) { bytes[position] = (byte)(unsigned >> 24); bytes[position + 1] = (byte)(unsigned >> 16); bytes[position + 2] = (byte)(unsigned >> 8); bytes[position + 3] = (byte)unsigned; } else { bytes[position] = (byte)unsigned; bytes[position + 1] = (byte)(unsigned >> 8); bytes[position + 2] = (byte)(unsigned >> 16); bytes[position + 3] = (byte)(unsigned >> 24); } } }
/// <summary> /// Reads a <see cref="double"/> value from an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to read from.</param> /// <param name="position">The position in the array where the value should be read.</param> /// <param name="endianness">The endianness.</param> /// <returns>The value.</returns> public static double ReadDouble(this byte[] bytes, int position, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfDouble); long value; unchecked { value = endianness.IsBigEndian() ? (long)bytes[position] << 56 | (long)bytes[position + 1] << 48 | (long)bytes[position + 2] << 40 | (long)bytes[position + 3] << 32 | (long)bytes[position + 4] << 24 | (long)bytes[position + 5] << 16 | (long)bytes[position + 6] << 8 | bytes[position + 7] : bytes[position] | (long)bytes[position + 1] << 8 | (long)bytes[position + 2] << 16 | (long)bytes[position + 3] << 24 | (long)bytes[position + 4] << 32 | (long)bytes[position + 5] << 40 | (long)bytes[position + 6] << 48 | (long)bytes[position + 7] << 56; } // this is essentially an unsafe *((double*)&value) return(BitConverter.Int64BitsToDouble(value)); }
/// <summary> /// Reads a <see cref="float"/> value from an array of bytes. /// </summary> /// <param name="bytes">The array of bytes to read from.</param> /// <param name="position">The position in the array where the value should be read.</param> /// <param name="endianness">The endianness.</param> /// <returns>The value.</returns> public static float ReadFloat(this byte[] bytes, int position, Endianness endianness) { Debug.Assert(bytes != null && position >= 0 && bytes.Length >= position + SizeOfFloat); int value; unchecked { value = endianness.IsBigEndian() ? bytes[position] << 24 | bytes[position + 1] << 16 | bytes[position + 2] << 8 | bytes[position + 3] : bytes[position] | bytes[position + 1] << 8 | bytes[position + 2] << 16 | bytes[position + 3] << 24; } #if NETSTANDARD2_0 return(BitConverter.ToSingle(BitConverter.GetBytes(value), 0)); #else // this is essentially an unsafe *((float*)&value) return(BitConverter.Int32BitsToSingle(value)); #endif }