示例#1
0
        internal object InitializeObject(object instance, Type type, STUInstanceField[] writtenFields,
                                         BinaryReader reader)
        {
            Dictionary <uint, FieldInfo> fieldMap = CreateFieldMap(GetValidFields(type));

            uint?instanceChecksum = (Attribute.GetCustomAttribute(instance.GetType(), typeof(STUAttribute), false) as STUAttribute)?.Checksum;

            if (instance is STUInstance stuInstance && instanceChecksum != null)
            {
                stuInstance.InstanceChecksum = (uint)instanceChecksum;
            }

            foreach (STUInstanceField writtenField in writtenFields)
            {
                if (!fieldMap.ContainsKey(writtenField.FieldChecksum))
                {
                    Debugger.Log(0, "STU",
                                 $"[STU:{type}]: Unknown field {writtenField.FieldChecksum:X8} ({writtenField.FieldSize} bytes)\n");
                    if (writtenField.FieldSize == 0)
                    {
                        uint size = reader.ReadUInt32();
                        reader.BaseStream.Position += size;
                        continue;
                    }
                    reader.BaseStream.Position += writtenField.FieldSize;
                    continue;
                }
                FieldInfo         field   = fieldMap[writtenField.FieldChecksum];
                STUFieldAttribute element = field.GetCustomAttribute <STUFieldAttribute>() ?? new STUFieldAttribute();
                bool skip = false;
                if (element?.STUVersionOnly != null)
                {
                    skip = element.STUVersionOnly.All(version => version != Version);
                }
                if (element?.IgnoreVersion != null && skip)
                {
                    skip = !element.IgnoreVersion.Any(stufield => stufield == writtenField.FieldChecksum);
                }
                if (skip)
                {
                    continue;
                }
                if (!CheckCompatVersion(field, BuildVersion))
                {
                    continue;
                }
                if (field.FieldType.IsArray)
                {
                    field.SetValue(instance, InitializeObjectArray(writtenField, field.FieldType.GetElementType(), reader, element));
                }
                else
                {
                    if (writtenField.FieldSize == 0)
                    {
                        if (field.FieldType.IsClass || field.FieldType.IsValueType)
                        {
                            STUInlineInfo inline         = reader.Read <STUInlineInfo>();
                            object        inlineInstance = Activator.CreateInstance(field.FieldType);
                            if (inline.FieldListIndex < 0 || inline.FieldListIndex >= InstanceFields.Length)
                            {
                                continue;
                            }
                            field.SetValue(instance,
                                           InitializeObject(inlineInstance, field.FieldType, InstanceFields[inline.FieldListIndex],
                                                            reader));
                            STUInstance fieldInstance = field.GetValue(instance) as STUInstance;
                            if (fieldInstance != null)
                            {
                                fieldInstance.Usage = InstanceUsage.Inline;
                            }
                            HiddenInstances.Add(fieldInstance);
                            continue;
                        }
                    }
                    if (writtenField.FieldSize == 4 && field.FieldType.IsClass && !IsSimple(field.FieldType) && typeof(STUInstance).IsAssignableFrom(field.FieldType))
                    {
                        int instanceIndex = reader.ReadInt32();  // sometimes the inline isn't defined in the instance
                        EmbedRequests.Add(new KeyValuePair <object, FieldInfo>(instance, field), instanceIndex);
                        // this is embedded, don't initialise the class
                        continue;
                    }

                    reader.BaseStream.Position += element.Padding;

                    long position = -1;
                    if (element?.ReferenceValue == true)
                    {
                        long offset = reader.ReadInt64();
                        if (offset == 0)
                        {
                            continue;
                        }
                        position = reader.BaseStream.Position;
                        reader.BaseStream.Position = offset;
                    }
                    field.SetValue(instance, GetValue(instance, writtenField, field.FieldType, reader, element, field));
                    if (position > -1)
                    {
                        reader.BaseStream.Position = position;
                    }
                }
                if (element?.Verify != null)
                {
                    if (!field.GetValue(instance).Equals(element.Verify))
                    {
                        throw new Exception("Verification failed");
                    }
                }

                if (element.Demangle)
                {
                    DemangleInstance(instance, writtenField.FieldChecksum);
                }
            }

            return(instance);
        }
示例#2
0
        internal object GetValue(object fieldOwner, Type type, BinaryReader reader, STUFieldAttribute element, FieldInfo fieldInfo, bool isArray = false, bool isInlineInstance = false)
        {
            if (type.IsArray)
            {
                long offset = reader.ReadInt64();
                if (offset == 0)
                {
                    return(Array.CreateInstance(type.GetElementType(), 0));
                }
                long position = reader.BaseStream.Position;
                reader.BaseStream.Position = offset + Start;
                if (element.EmbeddedInstance)
                {
                    throw new NotImplementedException();
                }
                object value = GetValueArray(type.GetElementType(), reader, element, fieldInfo);
                reader.BaseStream.Position = position + 8;
                return(value);
            }
            switch (type.Name)
            {
            case "String": {
                long offset = reader.ReadInt64();
                if (offset == 0)
                {
                    return(string.Empty);
                }
                long position = reader.BaseStream.Position;
                reader.BaseStream.Position = offset + Start;
                STUString stringData = reader.Read <STUString>();
                if (stringData.Size == 0)
                {
                    return(string.Empty);
                }
                reader.BaseStream.Position = stringData.Offset + Start;
                string @string = new string(reader.ReadChars((int)stringData.Size));
                reader.BaseStream.Position = position;
                return(@string);
            }

            case "Single":
                return(reader.ReadSingle());

            case "Boolean":
                return(reader.ReadByte() != 0);

            case "Int16":
                return(reader.ReadInt16());

            case "UInt16":
                return(reader.ReadUInt16());

            case "Int32":
                return(reader.ReadInt32());

            case "UInt32":
                return(reader.ReadUInt32());

            case "Int64":
                return(reader.ReadInt64());

            case "UInt64":
                return(reader.ReadUInt64());

            case "Byte":
                return(reader.ReadByte());

            case "SByte":
                return(reader.ReadSByte());

            case "Char":
                return(reader.ReadChar());

            default:
                if (type.GetInterfaces().Contains(typeof(ISTUCustomSerializable)))
                {
                    if (fieldInfo.FieldType.IsArray)
                    {
                        return(((ISTUCustomSerializable)Activator.CreateInstance(type)).DeserializeArray(fieldOwner, this, fieldInfo,
                                                                                                         reader, null));
                    }
                    return(((ISTUCustomSerializable)Activator.CreateInstance(type)).Deserialize(fieldOwner, this, fieldInfo,
                                                                                                reader, null));
                }
                if (type.IsEnum)
                {
                    return(Enum.ToObject(type, GetValue(fieldOwner, type.GetEnumUnderlyingType(), reader, element, fieldInfo, isArray)));
                }
                if (type.IsClass || type.IsValueType)
                {
                    if (!element.EmbeddedInstance)
                    {
                        return(InitializeObject(Activator.CreateInstance(type), type, reader, isArray, isInlineInstance && typeof(STUInstance).IsAssignableFrom(type)));
                    }
                    int index = reader.ReadInt32();
                    EmbedRequests.Add(new KeyValuePair <object, FieldInfo>(fieldOwner, fieldInfo), index);
                    return(null);
                }
                return(null);
            }
        }