Exemple #1
0
            private string DumpInstance(object instance, IndentHelper indentHelper, List <object> recursionGuard)
            {
                if (instance == null)
                {
                    return($"{indentHelper}STU_: unregistered");
                }
                FieldInfo[] fields = GetFields(instance.GetType()).Where(
                    fieldInfo => fieldInfo.GetCustomAttribute <STUFieldAttribute>()?.Checksum > 0).ToArray();

                string        ret               = "";
                string        lineStart         = "";
                List <object> newRecursionGuard = new List <object>(recursionGuard)
                {
                    instance
                };

                foreach (FieldInfo field in fields)
                {
                    if (field == null)
                    {
                        continue;
                    }
                    STUFieldAttribute element        = field.GetCustomAttribute <STUFieldAttribute>();
                    string            fieldNameThing = element.Name == null ? $"{element.Checksum:X8}" : $"{element.Name}";
                    ret      += $"{lineStart}{indentHelper}{field.DeclaringType?.Name}.{field.Name}|{fieldNameThing}: {DumpField(field, field.GetValue(instance), indentHelper, newRecursionGuard)}";
                    lineStart = "\r\n";
                }
                return(ret);
            }
Exemple #2
0
            private static string GetType(FieldInfo fieldInfo, Type type)
            {
                string ret = null;

                if (!type.IsClass || type == typeof(string))
                {
                    string valueName = type.Name;
                    if (ValueRenames.ContainsKey(valueName))
                    {
                        valueName = ValueRenames[valueName];
                    }
                    ret = valueName;
                }
                if (type == typeof(STUGUID))
                {
                    ret = "guid";
                }
                if (ret == null && type.IsArray)
                {
                    ret = type.GetElementType()?.Name;
                }
                if (ret == null)
                {
                    ret = type.Name;
                }

                if (IsSubclassOfRawGeneric(typeof(STUHashMap <>), type))
                {
                    Type subType = type.GetGenericArguments()[0];
                    ret = $"hashmap<{subType.Name}>";
                }

                if (fieldInfo != null)
                {
                    STUFieldAttribute element = fieldInfo.GetCustomAttribute <STUFieldAttribute>();
                    if (element != null && typeof(STUInstance).IsAssignableFrom(type))
                    {
                        ret = element.EmbeddedInstance ? $"embed<{ret}>" : $"inline<{ret}>";
                    }
                }
                if (type.IsArray)
                {
                    ret = $"array<{ret}>";
                }
                return(ret);
            }
Exemple #3
0
        private object GetValueArray(Type type, STUFieldAttribute element, STUArrayInfo info, STUInstanceField writtenField)
        {
            Array array = Array.CreateInstance(type, info.Count);

            for (uint i = 0; i < info.Count; ++i)
            {
                if (element != null)
                {
                    Metadata.Position += element.Padding;
                }

                uint parent = 0;
                if (InstanceArrayRef?.Length > info.InstanceIndex)
                {
                    parent = InstanceArrayRef[info.InstanceIndex].Checksum;
                }
                array.SetValue(GetValueArrayInner(type, element, parent, writtenField.FieldChecksum), i);
            }
            return(array);
        }
Exemple #4
0
        internal object GetValueArray(Type type, BinaryReader reader, STUFieldAttribute element, FieldInfo fieldInfo)
        {
            long offset;
            int  size = 0;

            if (element?.ReferenceArray == true)
            {
                STUReferenceArray referenceInfo = reader.Read <STUReferenceArray>();
                offset = referenceInfo.DataOffset;
                reader.BaseStream.Position = referenceInfo.SizeOffset;
                for (long i = 0; i < referenceInfo.EntryCount; ++i)
                {
                    size = Math.Max(size, reader.ReadInt32());
                }
            }
            else
            {
                STUArray arrayInfo = reader.Read <STUArray>();
                offset = arrayInfo.Offset;
                size   = (int)arrayInfo.EntryCount;
            }
            if (size == -1)
            {
                return(null);
            }

            Array array = Array.CreateInstance(type, size);

            reader.BaseStream.Position = offset + Start;
            for (int i = 0; i < size; ++i)
            {
                array.SetValue(GetValue(null, type, reader, element, fieldInfo, true, typeof(STUInstance).IsAssignableFrom(type)), i);
                if (typeof(STUInstance).IsAssignableFrom(type))
                {
                    reader.ReadUInt32();
                }
                // array.SetValue(GetValue(null, type, reader, element, fieldInfo, true), i);
            }

            return(array);
        }
Exemple #5
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);
        }
Exemple #6
0
        private object InitializeObject(object instance, Type type, uint reference, uint checksum, BinaryReader reader, bool isArrayBuffer, bool demangle)
        {
            FieldInfo[] fields = GetFields(type);
            foreach (FieldInfo field in fields)
            {
                STUFieldAttribute element = field.GetCustomAttribute <STUFieldAttribute>();
                bool skip = false;
                if (element?.STUVersionOnly != null)
                {
                    skip = !element.STUVersionOnly.Any(version => version == Version);
                }
                if (element?.IgnoreVersion != null && skip)
                {
                    skip = !element.IgnoreVersion.Any(stufield => stufield == reference);
                }
                if (skip)
                {
                    continue;
                }
                if (!CheckCompatVersion(field, BuildVersion))
                {
                    continue;
                }
                if (element?.OnlyBuffer == true && !isArrayBuffer)
                {
                    continue;
                }
                if (field.FieldType.IsArray)
                {
                    field.SetValue(instance, InitializeObjectArray(new STUInstanceField {
                        FieldChecksum = 0, FieldSize = 4
                    }, field.FieldType.GetElementType(), reader, element));
                }
                else
                {
                    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, new STUInstanceField {
                        FieldChecksum = 0,
                        FieldSize     = element == null || element.DummySize == -1 ? 4 : (uint)element.DummySize
                    },
                                                      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 (demangle)
            {
                DemangleInstance(instance, checksum);
            }

            return(instance);
        }
Exemple #7
0
        private object InitializeObjectArray(STUInstanceField field, Type type, BinaryReader reader, STUFieldAttribute element)
        {
            if (field.FieldSize == 0 && field.FieldChecksum != 0)
            {
                STUInlineArrayInfo inlineInfo = reader.Read <STUInlineArrayInfo>();
                if (inlineInfo.Size > 600000)
                {
                    return(null);                          // i feel that it's unlikley that there will be an inline with this count, exceptions if this isn't checked.
                }
                Array array = Array.CreateInstance(type, (uint)inlineInfo.Count);
                // if (inlineInfo.FieldListIndex == 0) return array;
                for (uint i = 0; i < (uint)inlineInfo.Count; ++i)
                {
                    Stream.Position += element.Padding;
                    uint   fieldIndex = reader.ReadUInt32();
                    object instance   = Activator.CreateInstance(type);
                    if (fieldIndex >= InstanceFieldLists.Length)
                    {
                        continue;
                    }
                    array.SetValue(InitializeObject(instance, type, InstanceFields[fieldIndex], reader), i);
                    STUInstance fieldInstance = array.GetValue(i) as STUInstance;
                    if (fieldInstance != null)
                    {
                        fieldInstance.Usage = InstanceUsage.InlineArray;
                    }
                    HiddenInstances.Add(fieldInstance);
                }
                return(array);
            }
            if (typeof(STUInstance).IsAssignableFrom(type))
            {
                int embedArrayOffset = reader.ReadInt32();
                Metadata.Position = embedArrayOffset;
                STUEmbedArrayInfo embedArrayInfo = MetadataReader.Read <STUEmbedArrayInfo>();

                if (embedArrayInfo.Count == 0)
                {
                    return(null);
                }
                Metadata.Position = embedArrayInfo.Offset;

                Array array = Array.CreateInstance(type, embedArrayInfo.Count);

                List <int> request = new List <int>();
                for (int i = 0; i < embedArrayInfo.Count; i++)
                {
                    int instanceIndex = MetadataReader.ReadInt32();
                    MetadataReader.ReadInt32(); // Padding
                    if (instanceIndex == -1)
                    {
                        return(null);
                    }
                    request.Add(instanceIndex);
                }
                EmbedArrayRequests[array] = request.ToArray();
                return(array);
            }
            int offset = reader.ReadInt32();

            Metadata.Position = offset;
            STUArrayInfo arrayInfo = MetadataReader.Read <STUArrayInfo>();

            Metadata.Position = arrayInfo.Offset;
            return(GetValueArray(type, element, arrayInfo, field));
        }
Exemple #8
0
        // ReSharper disable once UnusedParameter.Local
        private object GetValue(object fieldOwner, STUInstanceField field, Type type, BinaryReader reader, STUFieldAttribute element, FieldInfo fieldInfo)
        {
            if (type.IsArray)
            {
                return(InitializeObjectArray(field, type.GetElementType(), reader, element));
            }
            switch (type.Name)
            {
            case "String": {
                int stringPos = reader.ReadInt32();
                if (stringPos == -1)
                {
                    return(null);
                }
                Metadata.Position = stringPos;
                return(ReadMetadataString());
            }

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

            case "Int16":
            case "UInt16":
            case "Int32":
            case "UInt32":
            case "Int64":
            case "UInt64":
            case "SByte":
            case "Byte":
            case "Char":
                return(GetPrimitiveVarValue(reader, field, type));

            case "Boolean":
                return((byte)GetPrimitiveVarValue(reader, field, typeof(byte)) != 0);

            case "Object":
                reader.BaseStream.Position += 4;
                return(null);

            default:
                if (type.GetInterfaces().Contains(typeof(ISTUCustomSerializable)))
                {
                    return(((ISTUCustomSerializable)Activator.CreateInstance(type)).Deserialize(fieldOwner, this, fieldInfo,
                                                                                                reader, MetadataReader));
                }
                if (typeof(STUInstance).IsAssignableFrom(type))
                {
                    return(null);    // Set later by the second pass. Usually this is uint, indicating which STU instance entry to load inorder to get the instance. However this is only useful when you're streaming specific STUs.
                }
                if (type.IsEnum)
                {
                    return(GetValue(fieldOwner, field, type.GetEnumUnderlyingType(), reader, element, null));
                }
                if (type.IsClass)
                {
                    return(InitializeObject(Activator.CreateInstance(type), type, field.FieldChecksum, field.FieldChecksum, reader, element.FakeBuffer, element.Demangle));
                }
                if (type.IsValueType)
                {
                    return(InitializeObject(Activator.CreateInstance(type), type, CreateInstanceFields(type),
                                            reader));
                }
                return(null);
            }
        }
Exemple #9
0
        // ReSharper disable once UnusedParameter.Local
        private object GetValueArrayInner(Type type, STUFieldAttribute element, uint parent, uint checksum)
        {
            BinaryReader reader = MetadataReader;

            switch (type.Name)
            {
            case "String":
                long offset = MetadataReader.ReadInt64();
                long unk    = MetadataReader.ReadInt64();

                long beforePos = MetadataReader.BaseStream.Position;

                MetadataReader.BaseStream.Position = offset;
                string outString = ReadMetadataString();
                MetadataReader.BaseStream.Position = beforePos;      // idk if this is important
                return(outString);

            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 "Object":
                reader.BaseStream.Position += 4;
                return(null);

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

            default:
                if (type.IsEnum)
                {
                    return(Enum.ToObject(type, GetValueArrayInner(type.GetEnumUnderlyingType(), element, parent, checksum)));
                }
                if (type.IsClass || type.IsValueType)
                {
                    return(InitializeObject(Activator.CreateInstance(type), type, parent, checksum, reader, !element.ForceNotBuffer, element.Demangle));
                }
                return(null);
            }
        }
Exemple #10
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);
            }
        }
Exemple #11
0
        private object InitializeObject(object instance, Type type, BinaryReader reader, bool isArray, bool isInlineInstance)
        {
            FieldInfo[] fields = GetFields(type);
            foreach (FieldInfo field in fields)
            {
                STUFieldAttribute element = field.GetCustomAttribute <STUFieldAttribute>();
                bool skip = false;
                if (element?.STUVersionOnly != null)
                {
                    skip = element.STUVersionOnly.All(version => version != Version);
                }
                if (element != null)
                {
                    if (isArray && element.OnlyBuffer)
                    {
                        skip = true;
                    }
                }

                // todo: I thought that this was needed, but turns out that it breaks everything
                //if (isInlineInstance && (field.Name == nameof(STUInstance.InstanceChecksum) ||
                //                         field.Name == nameof(STUInstance.NextInstanceOffset))) skip = true;

                if (skip)
                {
                    continue;
                }
                if (!CheckCompatVersion(field, _buildVersion))
                {
                    continue;
                }
                if (field.FieldType.IsArray)
                {
                    long offset = reader.ReadInt64();
                    if (offset == 0 || offset <= -1)
                    {
                        field.SetValue(instance, Array.CreateInstance(field.FieldType.GetElementType(), 0));
                        continue;
                    }
                    long position = reader.BaseStream.Position;
                    reader.BaseStream.Position = offset + Start;
                    if (element?.EmbeddedInstance == true)
                    {
                        long[] offsets = (long[])GetValueArray(typeof(long), reader, element, field);
                        Array  array   = Array.CreateInstance(field.FieldType.GetElementType(), offsets.Length);
                        EmbedArrayRequests.Add(array, offsets.Select(x => (int)x).ToArray());
                        field.SetValue(instance, array);
                    }
                    else
                    {
                        field.SetValue(instance, GetValueArray(field.FieldType.GetElementType(), reader, element, field));
                    }
                    reader.BaseStream.Position = position + 8;
                }
                else
                {
                    long position = -1;
                    if (element?.ReferenceValue == true)
                    {
                        long offset = reader.ReadInt64();
                        if (offset == 0)
                        {
                            continue;
                        }
                        position = reader.BaseStream.Position;
                        reader.BaseStream.Position = offset + Start;
                    }
                    field.SetValue(instance, GetValue(instance, field.FieldType, reader, element, field, false, true));
                    if (position > -1)
                    {
                        reader.BaseStream.Position = position;
                    }
                }
                if (element?.Verify != null)
                {
                    if (!field.GetValue(instance).Equals(element.Verify))
                    {
                        throw new Exception("Verification failed");
                    }
                }
            }

            return(instance);
        }