using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; namespace skyscraper5.DNS.Protocol.Marshalling { internal class Struct { public static T GetStruct(byte[] data, int offset, int length) where T : struct { byte[] buffer = new byte[length]; Array.Copy(data, offset, buffer, 0, buffer.Length); GCHandle handle = GCHandle.Alloc(ConvertEndian(buffer), GCHandleType.Pinned); try { return Marshal.PtrToStructure(handle.AddrOfPinnedObject()); } finally { handle.Free(); } } private static byte[] ConvertEndian(byte[] data) { Type type = typeof(T); FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); EndianAttribute endian = null; if (type.GetTypeInfo().IsDefined(typeof(EndianAttribute), false)) { endian = (EndianAttribute)type.GetTypeInfo().GetCustomAttributes(typeof(EndianAttribute), false).First(); } foreach (FieldInfo field in fields) { if (endian == null && !field.IsDefined(typeof(EndianAttribute), false)) { continue; } int offset = Marshal.OffsetOf(field.Name).ToInt32(); #pragma warning disable 618 int length = Marshal.SizeOf(field.FieldType); #pragma warning restore 618 endian = endian ?? (EndianAttribute)field.GetCustomAttributes(typeof(EndianAttribute), false).First(); if (endian.Endianness == Endianness.Big && BitConverter.IsLittleEndian || endian.Endianness == Endianness.Little && !BitConverter.IsLittleEndian) { Array.Reverse(data, offset, length); } } return data; } public static byte[] GetBytes(T obj) where T : struct { byte[] data = new byte[Marshal.SizeOf(obj)]; GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); try { Marshal.StructureToPtr(obj, handle.AddrOfPinnedObject(), false); return ConvertEndian(data); } finally { handle.Free(); } } } }