/// <summary> /// Examines the specified type and calculates necessary information /// about the layout of the structure. /// </summary> private static void LoadData() { data = new List <SortedFieldInfo>(); Type sortingType = typeof(T); // insert sort foreach (FieldInfo fi in sortingType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { SortedFieldInfo info = new SortedFieldInfo(); info.field = fi; info.offset = OffsetOf(fi); int insertIndex = data.Count; while (insertIndex > 0 && info.offset <= data[insertIndex - 1].offset) { insertIndex--; } data.Insert(insertIndex, info); } // Adjust reference type size to zero (arrays, lists, strings) int omittedBytes = 0; for (int i = 0; i < data.Count; i++) { SortedFieldInfo dat = data[i]; int originalOffset = dat.offset; dat.offset -= omittedBytes; data[i] = dat; Type type = dat.field.FieldType; if (typeof(IHandle).IsAssignableFrom(type)) // Handle // Handle is 4 bytes { omittedBytes += (Marshal.SizeOf(type) - 4); } else if (type.IsSubclassOf(typeof(ValueType)) && !type.IsSubclassOf(typeof(System.Enum)) && !type.IsPrimitive) { // Struct could have any # of omitted bytes omittedBytes += getOmittedBytesFor_Dynamic(dat.field.FieldType); } else if (!data[i].field.FieldType.IsValueType) { // Ref is 4 bytes if (i < data.Count - 1) { // just in case of alignment issues omittedBytes += data[i + 1].offset - originalOffset; } else { omittedBytes += 4; } } } compactSize = Marshal.SizeOf(typeof(T)) - omittedBytes; SortedFieldData <T> .omittedBytes = omittedBytes; }
/// <summary> /// Creates a byte array contianing a structure with array references expanded to their contents. See remarks. /// </summary> /// <param name="t">The type of the structure.</param> /// <returns>The binary data of the structure.</returns> /// <remarks> /// <para>Valid Types: The specified object must be a structure. The only valid reference types /// (including contents of arrays and their subfields, recursively) /// are strings, string builders, arrays and generic IList objects. ILists and /// StringBuilders will be treated as arrays and strings, respectively.</para> /// /// <para>Encoding: Strings will be written as ASNI strings unless /// the field name ends with an encoding specifier (_UTF, _UTF7, _UTF8, _UTF32). Chars will /// always be ANSI. Store chars in a 1-char string field to specify encoding. Arrays of /// strings will always be ANSI. Concatenate string arrays into a single-string composite /// field to specify encoding).</para> /// /// Strings and arrays /// will not be prefixed with their length. Invalid objects may be silently omitted. /// IHandle objects will be treated as IntPtrs.</remarks> public static Byte[] ExpandArraysInStruct <T>(T obj, out int insertedByteCount) where T : struct { Type type = typeof(T); IList <SortedFieldInfo> fields = SortedFieldData <T> .Data; MemoryStream result = new MemoryStream(1); BinaryWriter resultWriter = new BinaryWriter(result); int offsetAdjustment = 0; for (int i = 0; i < fields.Count; i++) { // Get data SortedFieldInfo field = fields[i]; int targetOffset = field.offset + offsetAdjustment; object value = fields[i].field.GetValue(obj); // Seek to output offset while (result.Capacity < targetOffset) { result.Capacity *= 2; } result.Seek(targetOffset, SeekOrigin.Begin); // Write if (value is StringBuilder) { value = value.ToString(); } if (value is System.Enum) { value = GetEnumValue(value); } if (canWriteDirect(value)) { outputField(resultWriter, value); } else if (fields[i].field.FieldType.IsArray) { offsetAdjustment += outputList(resultWriter, fields[i].field.FieldType.GetElementType(), (System.Collections.IList)value); } else if (value is string || value is StringBuilder) { if (field.field.Name.EndsWith("_UTF")) { offsetAdjustment += WriteStringUTF(resultWriter, value); } else if (field.field.Name.EndsWith("_UTF7")) { offsetAdjustment += WriteStringUTF7(resultWriter, value); } else if (field.field.Name.EndsWith("_UTF8")) { offsetAdjustment += WriteStringUTF8(resultWriter, value); } else if (field.field.Name.EndsWith("_UTF32")) { offsetAdjustment += WriteStringUTF32(resultWriter, value); } else { offsetAdjustment += WriteString(resultWriter, value); } } else if (objectImplementsGenerigIList(value)) { offsetAdjustment += outputList(resultWriter, value.GetType().GetGenericArguments()[0], (System.Collections.IList)value); } else if (value is ValueType) { int extraBytes; byte[] structData = ExpandArraysInStruct_Dynamic(value, out extraBytes); result.Write(structData, 0, structData.Length); offsetAdjustment += extraBytes; } } insertedByteCount = offsetAdjustment; result.Capacity = (int)result.Length; return(result.GetBuffer()); }