internal void WriteInstance(MemberDefinition definition, Type propertyType, object node) { if (definition.ArraySize == 0) { WriteElement(definition, propertyType, node); return; } if (propertyType.IsArray) { // If the property is a native array (ie. SomeType[]), create an array instance and set its values var elementType = propertyType.GetElementType(); Array arr = node as Array; Debug.Assert(arr.Length == definition.ArraySize); for (int i = 0; i < definition.ArraySize; i++) { WriteElement(definition, elementType, arr.GetValue(i)); } } else { // For non-native arrays we always assume the property is an IList<T> var items = node as System.Collections.IList; var elementType = items.GetType().GetGenericArguments().Single(); foreach (var element in items) { WriteElement(definition, elementType, element); } } }
public void Write(GR2Writer writer, WritableSection section, MemberDefinition member, object obj) { var items = obj as List <UInt16>; for (int i = 0; i < items.Count; i++) { section.Writer.Write(items[i]); } }
public object Read(GR2Reader gr2, StructDefinition definition, MemberDefinition member, uint arraySize, object parent) { var controls = new List <UInt16>((int)arraySize); for (int i = 0; i < arraySize; i++) { controls.Add(gr2.Reader.ReadUInt16()); } return(controls); }
public void WriteMemberDefinition(MemberDefinition defn) { Writer.Write((UInt32)defn.Type); WriteStringReference(defn.GrannyName); WriteStructReference(defn.WriteDefinition); Writer.Write(defn.ArraySize); for (var i = 0; i < MemberDefinition.ExtraTagCount; i++) { Writer.Write(defn.Extra[i]); } if (GR2.Magic.Is32Bit) { Writer.Write(defn.Unknown); } else { Writer.Write((UInt64)defn.Unknown); } }
public void LoadFromType(Type type, GR2Writer writer) { Type = type; var attrs = type.GetCustomAttributes(typeof(StructSerializationAttribute), true); if (attrs.Length > 0) { StructSerializationAttribute serialization = attrs[0] as StructSerializationAttribute; MixedMarshal = serialization.MixedMarshal; } foreach (var field in type.GetFields(BindingFlags.Instance | BindingFlags.Public)) { var member = MemberDefinition.CreateFromFieldInfo(field, writer); if (member.SerializationKind != SerializationKind.None) { Members.Add(MemberDefinition.CreateFromFieldInfo(field, writer)); } } }
public void WriteStructDefinition(StructDefinition defn) { Debug.Assert(Writer == MainWriter); GR2.ObjectOffsets[defn] = new SectionReference(Type, (UInt32)MainStream.Position); var tag = GR2.Header.tag; foreach (var member in defn.Members) { if (member.ShouldSerialize(tag)) { WriteMemberDefinition(member); } } var end = new MemberDefinition(); end.Type = MemberType.None; end.Extra = new UInt32[] { 0, 0, 0 }; WriteMemberDefinition(end); }
internal void QueueStructWrite(SectionType section, bool dataArea, MemberDefinition member, Type type, object obj) { QueuedSerialization serialization; serialization.section = section; serialization.dataArea = dataArea; if (member.PreferredSection != SectionType.Invalid) { serialization.section = member.PreferredSection; } else if (member.SectionSelector != null) { serialization.section = member.SectionSelector.SelectSection(member, type, obj); } serialization.type = type; serialization.member = member; serialization.obj = obj; Sections[(int)serialization.section].CheckMixedMarshalling(obj, type, 1); StructWrites.Add(serialization); }
private object ReadElement(MemberDefinition definition, object node, Type propertyType, object parent) { #if DEBUG_GR2_SERIALIZATION var offsetInFile = Stream.Position; #endif var kind = definition.SerializationKind; Debug.Assert(kind == SerializationKind.Builtin || !definition.IsScalar); if (node == null && propertyType != null && !definition.IsScalar && (kind == SerializationKind.Builtin || kind == SerializationKind.UserElement) && // Variant construction is a special case as we don't know the struct defn beforehand definition.Type != MemberType.VariantReference) { node = Helpers.CreateInstance(propertyType); } switch (definition.Type) { case MemberType.Inline: Debug.Assert(definition.Definition.IsValid); #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(String.Format(" === Inline Struct {0} === ", definition.Name)); #endif if (kind == SerializationKind.UserElement || kind == SerializationKind.UserMember) { node = definition.Serializer.Read(this, definition.Definition.Resolve(this), definition, 0, parent); } else { node = ReadStruct(definition.Definition.Resolve(this), definition.Type, node, parent); } #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(" === End Struct === "); #endif break; case MemberType.Reference: { Debug.Assert(definition.Definition.IsValid); var r = ReadReference(); if (r.IsValid && parent != null) { var originalPos = Stream.Position; Seek(r); #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(String.Format(" === Struct <{0}> at {1:X8} === ", definition.Name, Stream.Position)); #endif if (kind == SerializationKind.UserElement || kind == SerializationKind.UserMember) { node = definition.Serializer.Read(this, definition.Definition.Resolve(this), definition, 0, parent); } else { node = ReadStruct(definition.Definition.Resolve(this), definition.Type, node, parent); } #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(" === End Struct === "); #endif Stream.Seek(originalPos, SeekOrigin.Begin); } else { node = null; } break; } case MemberType.VariantReference: { var structRef = ReadStructReference(); var r = ReadReference(); if (r.IsValid && parent != null) { var structDefn = structRef.Resolve(this); if (definition.TypeSelector != null && definition.Type == MemberType.VariantReference) { propertyType = definition.TypeSelector.SelectType(definition, structDefn, parent); } if (propertyType != null) { node = Helpers.CreateInstance(propertyType); } if (node != null) { var originalPos = Stream.Position; Seek(r); #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(String.Format(" === Variant Struct <{0}> at {1:X8} === ", definition.Name, Stream.Position)); #endif if (kind == SerializationKind.UserElement || kind == SerializationKind.UserMember) { node = definition.Serializer.Read(this, structDefn, definition, 0, parent); } else { node = ReadStruct(structRef.Resolve(this), definition.Type, node, parent); } #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(" === End Struct === "); #endif Stream.Seek(originalPos, SeekOrigin.Begin); } } else { node = null; } break; } case MemberType.ArrayOfReferences: { // Serializing as a struct member is nooooot a very good idea here. Debug.Assert(kind != SerializationKind.UserMember); Debug.Assert(definition.Definition.IsValid); var indices = ReadArrayIndicesReference(); #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(String.Format(" Array of references at [{0:X8}]", indices.Offset)); #endif Debug.Assert(indices.IsValid == (indices.Size != 0)); if (indices.IsValid && node != null && parent != null) { var items = node as System.Collections.IList; var type = items.GetType().GetGenericArguments().Single(); var refs = indices.Resolve(this); var originalPos = Stream.Position; for (int i = 0; i < refs.Count; i++) { Seek(refs[i]); #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(String.Format(" === Struct <{0}> at {1:X8} === ", definition.Name, Stream.Position)); #endif if (kind == SerializationKind.UserElement) { object element = definition.Serializer.Read(this, definition.Definition.Resolve(this), definition, 0, parent); items.Add(element); } else { object element = Helpers.CreateInstance(type); // TODO: Only create a new instance if we don't have a CachedStruct available! element = ReadStruct(definition.Definition.Resolve(this), definition.Type, element, parent); items.Add(element); } #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(" === End Struct === "); #endif } Stream.Seek(originalPos, SeekOrigin.Begin); node = items; } else { node = null; } break; } case MemberType.ReferenceToArray: case MemberType.ReferenceToVariantArray: { StructReference structRef; if (definition.Type == MemberType.ReferenceToVariantArray) { structRef = ReadStructReference(); } else { structRef = definition.Definition; } var itemsRef = ReadArrayReference(); Debug.Assert(itemsRef.IsValid == (itemsRef.Size != 0)); if (itemsRef.IsValid && parent != null && (node != null || kind == SerializationKind.UserMember)) { Debug.Assert(structRef.IsValid); var structType = structRef.Resolve(this); var originalPos = Stream.Position; Seek(itemsRef); if (kind == SerializationKind.UserMember) { // For ReferenceTo(Variant)Array, we start serialization after resolving the array ref itself. node = definition.Serializer.Read(this, structType, definition, itemsRef.Size, parent); } else { var items = node as System.Collections.IList; var type = items.GetType().GetGenericArguments().Single(); if (definition.Type == MemberType.ReferenceToVariantArray && kind != SerializationKind.UserElement && definition.TypeSelector != null) { type = definition.TypeSelector.SelectType(definition, structType, parent); } for (int i = 0; i < itemsRef.Size; i++) { #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(String.Format(" === Struct <{0}> at {1:X8} === ", definition.Name, Stream.Position)); #endif if (kind == SerializationKind.UserElement) { object element = definition.Serializer.Read(this, structType, definition, 0, parent); items.Add(element); } else { object element = Helpers.CreateInstance(type); element = ReadStruct(structType, definition.Type, element, parent); items.Add(element); } #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(" === End Struct === "); #endif } } Stream.Seek(originalPos, SeekOrigin.Begin); } else { node = null; } break; } case MemberType.String: var str = ReadStringReference(); if (str.IsValid) { node = str.Resolve(this); } else { node = null; } break; case MemberType.Transform: var transform = new Transform(); transform.Flags = Reader.ReadUInt32(); for (int i = 0; i < 3; i++) { transform.Translation[i] = Reader.ReadSingle(); } transform.Rotation.X = Reader.ReadSingle(); transform.Rotation.Y = Reader.ReadSingle(); transform.Rotation.Z = Reader.ReadSingle(); transform.Rotation.W = Reader.ReadSingle(); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { transform.ScaleShear[i, j] = Reader.ReadSingle(); } } node = transform; break; case MemberType.Real16: throw new NotImplementedException("TODO"); case MemberType.Real32: node = Reader.ReadSingle(); break; case MemberType.Int8: case MemberType.BinormalInt8: node = Reader.ReadSByte(); break; case MemberType.UInt8: case MemberType.NormalUInt8: node = Reader.ReadByte(); break; case MemberType.Int16: case MemberType.BinormalInt16: node = Reader.ReadInt16(); break; case MemberType.UInt16: case MemberType.NormalUInt16: node = Reader.ReadUInt16(); break; case MemberType.Int32: node = Reader.ReadInt32(); break; case MemberType.UInt32: node = Reader.ReadUInt32(); break; default: throw new ParsingException(String.Format("Unhandled member type: {0}", definition.Type.ToString())); } #if DEBUG_GR2_SERIALIZATION if (node != null) { System.Console.WriteLine(String.Format(" [{0:X8}] {1}: {2}", offsetInFile, definition.Name, node.ToString())); } else { System.Console.WriteLine(String.Format(" [{0:X8}] {1}: <null>", offsetInFile, definition.Name)); } #endif return(node); }
internal object ReadInstance(MemberDefinition definition, object node, Type propertyType, object parent) { if (definition.SerializationKind == SerializationKind.UserRaw) { return(definition.Serializer.Read(this, null, definition, 0, parent)); } if (definition.ArraySize == 0) { return(ReadElement(definition, node, propertyType, parent)); } Type elementType = null; if (propertyType != null) { if (definition.SerializationKind == SerializationKind.UserMember) { // Do unserialization directly on the whole array if per-member serialization was requested. // This mode is a bit odd, as we resolve StructRef-s for non-arrays, but don't for array types. StructDefinition defn = null; if (definition.Definition.IsValid) { defn = definition.Definition.Resolve(this); } return(definition.Serializer.Read(this, defn, definition, definition.ArraySize, parent)); } else if (propertyType.IsArray) { // If the property is a native array (ie. SomeType[]), create an array instance and set its values elementType = propertyType.GetElementType(); Array objs = Helpers.CreateArrayInstance(propertyType, (int)definition.ArraySize) as Array; for (int i = 0; i < definition.ArraySize; i++) { objs.SetValue(ReadElement(definition, objs.GetValue(i), elementType, parent), i); } return(objs); } else { // For non-native arrays we always assume the property is an IList<T> if (node == null) { node = Helpers.CreateInstance(propertyType); } var items = node as System.Collections.IList; var type = items.GetType().GetGenericArguments().Single(); for (int i = 0; i < definition.ArraySize; i++) { items.Add(ReadElement(definition, null, elementType, parent)); } return(items); } } else { for (int i = 0; i < definition.ArraySize; i++) { ReadElement(definition, null, null, parent); } return(null); } }
public MemberDefinition ReadMemberDefinition() { #if DEBUG_GR2_SERIALIZATION var defnOffset = Stream.Position; #endif var defn = new MemberDefinition(); int typeId = Reader.ReadInt32(); if (typeId > (uint)MemberType.Max) { throw new ParsingException(String.Format("Unsupported member type: {0}", typeId)); } defn.Type = (MemberType)typeId; var name = ReadStringReference(); Debug.Assert(!defn.IsValid || name.IsValid); if (defn.IsValid) { defn.Name = name.Resolve(this); defn.GrannyName = defn.Name; } defn.Definition = ReadStructReference(); defn.ArraySize = Reader.ReadUInt32(); defn.Extra = new UInt32[MemberDefinition.ExtraTagCount]; for (var i = 0; i < MemberDefinition.ExtraTagCount; i++) { defn.Extra[i] = Reader.ReadUInt32(); } // TODO 64-bit: ??? if (Magic.Is32Bit) { defn.Unknown = Reader.ReadUInt32(); } else { defn.Unknown = (UInt32)Reader.ReadUInt64(); } Debug.Assert(defn.Unknown == 0); if (defn.Type == MemberType.Inline || defn.Type == MemberType.Reference || defn.Type == MemberType.ArrayOfReferences || defn.Type == MemberType.ReferenceToArray) { Debug.Assert(defn.Definition.IsValid); } #if DEBUG_GR2_SERIALIZATION string description; if (defn.IsValid) { if (defn.ArraySize != 0) { description = String.Format(" [{0:X8}] {1}: {2}[{3}]", defnOffset, defn.Name, defn.Type.ToString(), defn.ArraySize); } else { description = String.Format(" [{0:X8}] {1}: {2}", defnOffset, defn.Name, defn.Type.ToString()); } if (defn.Definition.IsValid) { if (!DebugPendingResolve.Contains(defn.Definition)) { DebugPendingResolve.Add(defn.Definition); System.Console.WriteLine(String.Format(" ===== Debug resolve for {0:X8} ===== ", defn.Definition.Offset)); defn.Definition.Resolve(this); System.Console.WriteLine(String.Format(" ===== End debug resolve for {0:X8} ===== ", defn.Definition.Offset)); } description += String.Format(" <struct {0:X8}>", defn.Definition.Offset); } if (defn.Extra[0] != 0 || defn.Extra[1] != 0 || defn.Extra[2] != 0) { description += String.Format(" Extra: {0} {1} {2}", defn.Extra[0], defn.Extra[1], defn.Extra[2]); } } else { description = String.Format(" <invalid>: {0}", defn.Type.ToString()); } System.Console.WriteLine(description); #endif return(defn); }
public static MemberDefinition CreateFromFieldInfo(FieldInfo info, GR2Writer writer) { var member = new MemberDefinition(); var type = info.FieldType; member.Name = info.Name; member.GrannyName = info.Name; member.Extra = new UInt32[] { 0, 0, 0 }; member.CachedField = info; member.HasCachedField = true; member.LoadAttributes(info, writer); if (type.IsArray) { if (member.ArraySize == 0) { throw new InvalidOperationException("SerializationAttribute.ArraySize must be set for fixed size arrays"); } type = type.GetElementType(); } if (member.Type == MemberType.Invalid) { if (type == typeof(SByte)) { member.Type = MemberType.Int8; } else if (type == typeof(Byte)) { member.Type = MemberType.UInt8; } else if (type == typeof(Int16)) { member.Type = MemberType.Int16; } else if (type == typeof(UInt16)) { member.Type = MemberType.UInt16; } else if (type == typeof(Int32)) { member.Type = MemberType.Int32; } else if (type == typeof(UInt32)) { member.Type = MemberType.UInt32; } else if (type == typeof(Half)) { member.Type = MemberType.Real16; } else if (type == typeof(Single)) { member.Type = MemberType.Real32; } else if (type == typeof(string)) { member.Type = MemberType.String; } else if (type == typeof(Transform)) { member.Type = MemberType.Transform; } else if (type == typeof(object) || type.IsAbstract || type.IsInterface) { member.Type = MemberType.VariantReference; } else if (type.GetInterfaces().Contains(typeof(IList <object>))) { member.Type = MemberType.ReferenceToVariantArray; } else if (type.GetInterfaces().Contains(typeof(System.Collections.IList))) { member.Type = MemberType.ReferenceToArray; // or ArrayOfReferences? } else { member.Type = MemberType.Reference; // or Inline? } } if (member.SerializationKind != SerializationKind.None && member.WriteDefinition == null && writer != null) { if (member.Type == MemberType.Inline || member.Type == MemberType.Reference) { member.WriteDefinition = writer.LookupStructDefinition(type); } else if (member.Type == MemberType.ReferenceToArray || member.Type == MemberType.ArrayOfReferences) { member.WriteDefinition = writer.LookupStructDefinition(type.GetGenericArguments().Single()); } } return(member); }
private void WriteElement(MemberDefinition definition, Type propertyType, object node) { var type = definition.CachedField.FieldType; bool dataArea = definition.DataArea || (Writer == DataWriter); switch (definition.Type) { case MemberType.Inline: if (definition.SerializationKind == SerializationKind.UserMember) { definition.Serializer.Write(this.GR2, this, definition, node); } else { WriteStruct(type, node, false); } break; case MemberType.Reference: { WriteReference(node); if (node != null) { GR2.QueueStructWrite(Type, dataArea, definition, type, node); } break; } case MemberType.VariantReference: { if (node != null) { var inferredType = node.GetType(); if (definition.TypeSelector != null) { var variantType = definition.TypeSelector.SelectType(definition, node); if (variantType != null) { inferredType = variantType; } } WriteStructReference(GR2.LookupStructDefinition(inferredType, node)); WriteReference(node); GR2.QueueStructWrite(Type, dataArea, definition, inferredType, node); } else { WriteStructReference(null); WriteReference(null); } break; } case MemberType.ArrayOfReferences: { // Serializing as a struct member is nooooot a very good idea here. // Debug.Assert(kind != SerializationKind.UserMember); var list = node as System.Collections.IList; WriteArrayIndicesReference(list); if (list != null && list.Count > 0) { GR2.QueueArrayWrite(Type, dataArea, type.GetGenericArguments().Single(), definition, list); } break; } case MemberType.ReferenceToArray: { var list = node as System.Collections.IList; WriteArrayIndicesReference(list); if (list != null && list.Count > 0) { GR2.QueueArrayWrite(Type, dataArea, type.GetGenericArguments().Single(), definition, list); } break; } case MemberType.ReferenceToVariantArray: { var list = node as System.Collections.IList; if (list != null && list.Count > 0) { var inferredType = list[0].GetType(); if (definition.TypeSelector != null) { var variantType = definition.TypeSelector.SelectType(definition, node); if (variantType != null) { inferredType = variantType; } } WriteStructReference(GR2.LookupStructDefinition(inferredType, list[0])); WriteArrayIndicesReference(list); GR2.QueueArrayWrite(Type, dataArea, inferredType, definition, list); } else { WriteStructReference(null); WriteArrayIndicesReference(list); } break; } case MemberType.String: WriteStringReference(node as string); break; case MemberType.Transform: var transform = node as Transform; Writer.Write(transform.Flags); for (int i = 0; i < 3; i++) { Writer.Write(transform.Translation[i]); } Writer.Write(transform.Rotation.X); Writer.Write(transform.Rotation.Y); Writer.Write(transform.Rotation.Z); Writer.Write(transform.Rotation.W); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { Writer.Write(transform.ScaleShear[i, j]); } } break; case MemberType.Real16: Writer.Write((Half)node); break; case MemberType.Real32: Writer.Write((Single)node); break; case MemberType.Int8: case MemberType.BinormalInt8: Writer.Write((SByte)node); break; case MemberType.UInt8: case MemberType.NormalUInt8: Writer.Write((Byte)node); break; case MemberType.Int16: case MemberType.BinormalInt16: Writer.Write((Int16)node); break; case MemberType.UInt16: case MemberType.NormalUInt16: Writer.Write((UInt16)node); break; case MemberType.Int32: Writer.Write((Int32)node); break; case MemberType.UInt32: Writer.Write((UInt32)node); break; default: throw new ParsingException(String.Format("Unhandled member type: {0}", definition.Type.ToString())); } }
internal void WriteArray(MemberDefinition arrayDefn, Type elementType, System.Collections.IList list) { bool dataArea = arrayDefn.DataArea || (Writer == DataWriter); AlignWrite(); switch (arrayDefn.Type) { case MemberType.ArrayOfReferences: { // Serializing as a struct member is nooooot a very good idea here. // Debug.Assert(kind != SerializationKind.UserMember); // Reference lists are always written to the data area var oldWriter = Writer; Writer = DataWriter; StoreObjectOffset(list); for (int i = 0; i < list.Count; i++) { WriteReference(list[i]); GR2.QueueStructWrite(Type, dataArea, arrayDefn, elementType, list[i]); } Writer = oldWriter; break; } case MemberType.ReferenceToArray: case MemberType.ReferenceToVariantArray: { StoreObjectOffset(list); if (arrayDefn.SerializationKind == SerializationKind.UserMember) { arrayDefn.Serializer.Write(this.GR2, this, arrayDefn, list); } else if (arrayDefn.SerializationKind == SerializationKind.UserElement) { for (int i = 0; i < list.Count; i++) { StoreObjectOffset(list[i]); arrayDefn.Serializer.Write(this.GR2, this, arrayDefn, list[i]); } } else { for (int i = 0; i < list.Count; i++) { WriteStruct(elementType, list[i], false); } } GR2.FlushPendingWrites(); break; } default: throw new ParsingException(String.Format("Unhandled array member type: {0}", arrayDefn.Type.ToString())); } }
internal void QueueArrayWrite(SectionType section, bool dataArea, Type elementType, MemberDefinition member, System.Collections.IList list) { QueuedArraySerialization serialization; serialization.section = section; serialization.dataArea = dataArea; if (member.PreferredSection != SectionType.Invalid) { serialization.section = member.PreferredSection; } else if (member.SectionSelector != null) { serialization.section = member.SectionSelector.SelectSection(member, elementType, list); } serialization.elementType = elementType; serialization.member = member; serialization.list = list; Sections[(int)serialization.section].CheckMixedMarshalling(list[0], elementType, (UInt32)list.Count); ArrayWrites.Add(serialization); }