// using System.Runtime.InteropServices;
// using System.Linq;
// using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class EndianStructExtensionTests
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct Foo
{
public byte b1;
public short s;
public ushort S;
public int i;
public uint I;
public long l;
public ulong L;
public float f;
public double d;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string MyString;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct FooReversed
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string MyString;
public double d;
public float f;
public ulong L;
public long l;
public uint I;
public int i;
public ushort S;
public short s;
public byte b1;
}
byte[] _defaultBEBytes = new byte[] {
1,
0,1,
0,1,
0,0,0,1,
0,0,0,1,
0,0,0,0,0,0,0,1,
0,0,0,0,0,0,0,1,
0x3F,0X80,0,0, // float of 1 (see http://en.wikipedia.org/wiki/Endianness#Floating-point_and_endianness)
0x3F,0xF0,0,0,0,0,0,0, // double of 1
0,0,0,0x67,0x6E,0x69,0x74,0x73,0x65,0x54 // Testing\0\0\0
};
private FooReversed GetDefaultStruct()
{
FooReversed f;
f.b1 = 1;
f.s = 1;
f.S = 1;
f.i = 1;
f.I = 1;
f.l = 1;
f.L = 1;
f.f = 1.0f;
f.d = 1.0;
f.MyString = "Testing";
return f;
}
[TestMethod]
public void ToStructHostEndian_BEBytesOfValueOneForMostTypes_Matches()
{
byte[] bytes = _defaultBEBytes.Reverse().ToArray();
FooReversed expected = GetDefaultStruct();
FooReversed actual = bytes.ToStructureHostEndian<FooReversed>();
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void ToBytesHostEndian_DefaultStruct_BytesMatch()
{
byte[] expected = _defaultBEBytes.Reverse().ToArray();
byte[] actual = GetDefaultStruct().ToBytesHostEndian();
CollectionAssert.AreEqual(expected,actual);
}
}
public static class EndianExtensions
{
/// <summary>
/// Convert the bytes to a structure in host-endian format (little-endian on PCs).
/// To use with big-endian data, reverse all of the data bytes and create a struct that is in the reverse order of the data.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
public static T ToStructureHostEndian<T>(this byte[] buffer) where T : struct
{
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
handle.Free();
return stuff;
}
/// <summary>
/// Converts the struct to a byte array in the endianness of this machine.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="structure">The structure.</param>
/// <returns></returns>
public static byte[] ToBytesHostEndian<T>(this T structure) where T : struct
{
int size = Marshal.SizeOf(structure);
var buffer = new byte[size];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
Marshal.StructureToPtr(structure, handle.AddrOfPinnedObject(), true);
handle.Free();
return buffer;
}
}