public StructDefinition Resolve(GR2Reader gr2) { Debug.Assert(IsValid); // Type definitions use a 2-level cache // First we'll check the reference itself, if it has a cached ref to the resolved type // If it has, we have nothing to do // If the struct wasn't resolved yet, try the type definition cache // When a type definition is read from the GR2 file, it is stored here using its definition address as a key if (Type == null) { gr2.Types.TryGetValue(this, out Type); } if (Type == null) { // We haven't seen this type before, read its definition from the file and cache it #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(String.Format(" ===== Struct definition at {0:X8} ===== ", Offset)); #endif var originalPos = gr2.Stream.Position; gr2.Seek(this); Type = gr2.ReadStructDefinition(); gr2.Stream.Seek(originalPos, SeekOrigin.Begin); gr2.Types[this] = Type; } return(Type); }
internal void AddMixedMarshalling(object o, UInt32 count, StructDefinition type) { var marshal = new MixedMarshallingData(); marshal.Obj = o; marshal.Count = count; marshal.Type = type; MixedMarshalling.Add(marshal); }
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); }
private void LoadAttributes(FieldInfo info, GR2Writer writer) { var attrs = info.GetCustomAttributes(typeof(SerializationAttribute), true); if (attrs.Length > 0) { SerializationAttribute serialization = attrs[0] as SerializationAttribute; if (serialization.Section != SectionType.Invalid) { PreferredSection = serialization.Section; } DataArea = serialization.DataArea; if (serialization.Type != MemberType.Invalid) { Type = serialization.Type; } if (serialization.TypeSelector != null) { TypeSelector = Activator.CreateInstance(serialization.TypeSelector) as VariantTypeSelector; } if (serialization.SectionSelector != null) { SectionSelector = Activator.CreateInstance(serialization.SectionSelector) as SectionSelector; } if (serialization.Serializer != null) { Serializer = Activator.CreateInstance(serialization.Serializer) as NodeSerializer; } if (writer != null && serialization.Prototype != null) { WriteDefinition = writer.LookupStructDefinition(serialization.Prototype); } if (serialization.Name != null) { GrannyName = serialization.Name; } Prototype = serialization.Prototype; SerializationKind = serialization.Kind; ArraySize = serialization.ArraySize; MinVersion = serialization.MinVersion; MaxVersion = serialization.MaxVersion; } }
internal void WriteStruct(StructDefinition definition, object node, bool allowRecursion = true, bool allowAlign = true) { if (node == null) { throw new ArgumentNullException(); } if (allowAlign) { AlignWrite(); } StoreObjectOffset(node); var tag = GR2.Header.tag; foreach (var member in definition.Members) { if (member.ShouldSerialize(tag)) { var value = member.CachedField.GetValue(node); if (member.SerializationKind == SerializationKind.UserRaw) { member.Serializer.Write(this.GR2, this, member, value); } else { WriteInstance(member, member.CachedField.FieldType, value); } } } // When the struct is empty, we need to write a dummy byte to make sure that another // struct won't have the same address. if (definition.Members.Count == 0) { Writer.Write((Byte)0); } if (Writer == MainWriter && allowRecursion) { // We need to write all child structs directly after the parent struct // (at least this is how granny2.dll does it) GR2.FlushPendingWrites(); } }
internal StructDefinition LookupStructDefinition(Type type) { if (type.GetInterfaces().Contains(typeof(System.Collections.IList)) || type.IsArray || type.IsPrimitive) { throw new ArgumentException("Cannot create a struct definition for array or primitive types"); } StructDefinition defn = null; if (!Types.TryGetValue(type, out defn)) { defn = new StructDefinition(); Types.Add(type, defn); defn.LoadFromType(type, this); } return(defn); }
public StructDefinition ReadStructDefinition() { var defn = new StructDefinition(); while (true) { var member = ReadMemberDefinition(); if (member.IsValid) { defn.Members.Add(member); } else { break; } } return(defn); }
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); }
public void WriteStructReference(StructDefinition defn) { if (defn != null) { AddFixup(defn); if (!GR2.Types.ContainsKey(defn.Type)) { GR2.Types.Add(defn.Type, defn); } } if (GR2.Magic.Is32Bit) { Writer.Write((UInt32)0); } else { Writer.Write((UInt64)0); } }
private void MixedMarshal(UInt32 count, StructDefinition definition) { for (var arrayIdx = 0; arrayIdx < count; arrayIdx++) { foreach (var member in definition.Members) { var size = member.Size(this); if (member.Type == MemberType.Inline) { MixedMarshal(member.ArraySize == 0 ? 1 : member.ArraySize, member.Definition.Resolve(this)); } else if (member.MarshallingSize() > 1) { var marshalSize = member.MarshallingSize(); byte[] data = new byte[size]; Stream.Read(data, 0, (int)size); for (var j = 0; j < size / marshalSize; j++) { // Byte swap for 2, 4, 8-byte values for (var off = 0; off < marshalSize / 2; off++) { var tmp = data[j * marshalSize + off]; data[j * marshalSize + off] = data[j * marshalSize + marshalSize - 1 - off]; data[j * marshalSize + marshalSize - 1 - off] = tmp; } } Stream.Seek(-size, SeekOrigin.Current); Stream.Write(data, 0, (int)size); Stream.Seek(-size, SeekOrigin.Current); } Stream.Seek(size, SeekOrigin.Current); } } }
internal StructDefinition LookupStructDefinition(Type type, object instance) { StructDefinition defn = null; if (Types.TryGetValue(type, out defn)) { return(defn); } if (type.GetInterfaces().Contains(typeof(System.Collections.IList)) || type.IsArray || type.IsPrimitive) { throw new ArgumentException("Cannot create a struct definition for array or primitive types"); } var attrs = type.GetCustomAttributes(typeof(StructSerializationAttribute), true); if (attrs.Length > 0) { StructSerializationAttribute serialization = attrs[0] as StructSerializationAttribute; if (serialization.TypeSelector != null) { var selector = Activator.CreateInstance(serialization.TypeSelector) as StructDefinitionSelector; defn = selector.CreateStructDefinition(instance); Types.Add(type, defn); } } if (defn == null) { defn = new StructDefinition(); Types.Add(type, defn); defn.LoadFromType(type, this); } return(defn); }
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); } }
internal object ReadStruct(StructDefinition definition, MemberType memberType, object node, object parent) { var offset = (UInt32)Stream.Position; object cachedNode = null; if (memberType != MemberType.Inline && CachedStructs.TryGetValue(offset, out cachedNode)) { #if DEBUG_GR2_SERIALIZATION System.Console.WriteLine(String.Format("Skipped cached struct {1} at {0:X8}", offset, node.ToString())); #endif Stream.Position += definition.Size(this); return(cachedNode); } if (node != null) { // Don't save inline structs in the cached struct map, as they can occupy the same address as a non-inline struct // if they're at the beginning of said struct. // They also cannot be referenced from multiple locations, so caching them is of no use. if (memberType != MemberType.Inline) { CachedStructs.Add(offset, node); } #if DEBUG_GR2_FORMAT_DIFFERENCES // Create a struct definition from this instance and check if the GR2 type differs from the local type. var localDefn = new StructDefinition(); localDefn.LoadFromType(node.GetType(), null); var localMembers = localDefn.Members.Where(m => m.ShouldSerialize(Header.tag)).ToList(); var defnMembers = definition.Members.Where(m => m.ShouldSerialize(Header.tag)).ToList(); if (localMembers.Count != defnMembers.Count) { Trace.TraceWarning(String.Format("Struct {0} differs: Field count differs ({1} vs {2})", node.GetType().Name, localMembers.Count, defnMembers.Count)); } else { for (int i = 0; i < localMembers.Count; i++) { var member = localMembers[i]; var local = defnMembers[i]; if (member.Type != local.Type) { Trace.TraceWarning(String.Format( "Struct {0}: Field {1} type differs ({1} vs {2})", node.GetType().Name, local.Name, local.Type, member.Type )); } if (!member.GrannyName.Equals(local.GrannyName)) { Trace.TraceWarning(String.Format( "Struct {0}: Field {1} name differs ({1} vs {2})", node.GetType().Name, local.Name, local.GrannyName, member.GrannyName )); } if (member.ArraySize != local.ArraySize) { Trace.TraceWarning(String.Format( "Struct {0}: Field {1} array size differs ({1} vs {2})", node.GetType().Name, local.Name, local.ArraySize, member.ArraySize )); } } } #endif definition.MapType(node); foreach (var member in definition.Members) { var field = member.LookupFieldInfo(node); if (field != null) { var value = ReadInstance(member, field.GetValue(node), field.FieldType, node); field.SetValue(node, value); } else { ReadInstance(member, null, null, node); } } } else { foreach (var member in definition.Members) { ReadInstance(member, null, null, null); } } return(node); }