private PropertyInfo ReadProperty(BinaryReader Reader, FPropertyTag Tag = null) { var Info = new PropertyInfo(); if (Tag == null) { Info.Tag.Deserialize(Reader); } else { Info.Tag = Tag; } if (Info.Tag.Name == "None") { return(null); } if (Info.Tag.Size == 0) { return(Info); } if (Info.Tag.Type == "StructProperty") { if (!HardcodedStructs.ContainsKey(Info.Tag.StructName)) { // If it's not hardcoded it has tags for each field for (var Child = ReadProperty(Reader); Child != null; Child = ReadProperty(Reader)) { Info.Children.Add(Child); } return(Info); } Info.Prop = HardcodedStructs[Info.Tag.StructName](); } else if (Info.Tag.Type == "ArrayProperty") { var ArrayProp = new UArrayProperty(); ArrayProp.Deserialize(Reader); Info.Prop = ArrayProp; for (var i = 0; i < ArrayProp.Length; i++) { var Child = ReadProperty(Reader, ArrayProp.InnerTag); Child.ArrayIndex = i; Info.Children.Add(Child); } return(Info); } else { if (!PropertyConstructors.ContainsKey(Info.Tag.Type)) { // Unsupported type Info.UnsupportedData = Reader.ReadBytes(Info.Tag.Size); return(Info); } Info.Prop = PropertyConstructors[Info.Tag.Type](); } var Data = Reader.ReadBytes(Info.Tag.Size); using (var DataStream = new MemoryStream(Data)) { using (var DataReader = new BinaryReader(DataStream)) { Info.Prop.Deserialize(DataReader); } } return(Info); }
private PropertyInfo ReadProperty(BinaryReader Reader, FPropertyTag Tag = null) { var Info = new PropertyInfo(); if (Tag == null) { Info.Tag.Deserialize(Reader); } else { Info.Tag = Tag; } if (Info.Tag.Name == "None") { return(null); } if (Info.Tag.Type == "BoolProperty") { // Special handling for tagless bools in MapProperty if (Tag != null) { Info.Tag.BoolVal = Reader.ReadByte(); } return(Info); } else if (Info.Tag.Type == "StructProperty") { if (Info.Tag.StructName == null || !HardcodedStructs.ContainsKey(Info.Tag.StructName)) { // If it's not hardcoded it has tags for each field for (var Child = ReadProperty(Reader); Child != null; Child = ReadProperty(Reader)) { Child.Parent = Info; Info.Children.Add(Child); } return(Info); } Info.Prop = HardcodedStructs[Info.Tag.StructName](); } else if (Info.Tag.Type == "MapProperty") { var MapProp = new UMapProperty(); var StartOffset = Reader.BaseStream.Position; MapProp.Deserialize(Reader); Info.Prop = MapProp; for (var i = 0; i < MapProp.NumEntries; i++) { var Key = ReadProperty(Reader, new FPropertyTag(Info.Tag.InnerType)); Key.ArrayIndex = i; Key.KVType = PropertyInfo.KeyValueType.Key; Key.Parent = Info; Info.Children.Add(Key); var Value = ReadProperty(Reader, new FPropertyTag(Info.Tag.ValueType)); Value.ArrayIndex = i; Value.KVType = PropertyInfo.KeyValueType.Value; Value.Parent = Info; Info.Children.Add(Value); if (Key.FailureReason != null || Value.FailureReason != null) { // It's impossible to skip a MapProperty child that can't be deserialized because the size is unknown Reader.BaseStream.Seek(StartOffset, SeekOrigin.Begin); Info.RawData = Reader.ReadBytes(Info.Tag.Size); Info.FailureReason = "Failed to deserialize child: " + (Key.FailureReason ?? Value.FailureReason); Info.Children.Clear(); return(Info); } } return(Info); } else if (Info.Tag.Type == "ArrayProperty") { var ArrayProp = new UArrayProperty(); ArrayProp.Deserialize(Reader); Info.Prop = ArrayProp; for (var i = 0; i < ArrayProp.Length; i++) { var Child = ReadProperty(Reader, ArrayProp.InnerTag); Child.ArrayIndex = i; Child.Parent = Info; Info.Children.Add(Child); } return(Info); } else { if (!PropertyConstructors.ContainsKey(Info.Tag.Type)) { Info.RawData = Reader.ReadBytes(Info.Tag.Size); Info.FailureReason = "Unsupported type"; return(Info); } Info.Prop = PropertyConstructors[Info.Tag.Type](); } // UMapProperty does not provide a full tag for the inner types, so the size is unknown if (Tag != null && Tag.Size == 0) { try { Info.Prop.Deserialize(Reader); } catch (Exception e) { // Treat it the same as an unsupported property type Info.FailureReason = e.Message; Info.Prop = null; } return(Info); } Info.RawData = Reader.ReadBytes(Info.Tag.Size); using (var DataStream = new MemoryStream(Info.RawData)) { using (var DataReader = new BinaryReader(DataStream)) { try { Info.Prop.Deserialize(DataReader); } catch (Exception e) { // Treat it the same as an unsupported property type Info.FailureReason = e.Message; Info.Prop = null; } } } return(Info); }