Example #1
0
        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);
        }
Example #2
0
        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);
        }
Example #3
0
        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);
        }
Example #4
0
        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;
            }
        }
Example #5
0
        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();
            }
        }
Example #6
0
        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);
        }
Example #7
0
        public StructDefinition ReadStructDefinition()
        {
            var defn = new StructDefinition();

            while (true)
            {
                var member = ReadMemberDefinition();
                if (member.IsValid)
                {
                    defn.Members.Add(member);
                }
                else
                {
                    break;
                }
            }

            return(defn);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
            }
        }
Example #10
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);
                }
            }
        }
Example #11
0
        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);
        }
Example #12
0
        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);
            }
        }
Example #13
0
        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);
        }