示例#1
0
        // A method was called by our inspected method. We use the collected information (our environment)
        // to extract information about the type (and fields).
        public static void SerializeOnCall(CallInfo info, List <byte> writtenBytes,
                                           List <IRClassProperty> properties)
        {
            if (!info.Method.Name.StartsWith("Write") || info.Method.Name.StartsWith("WriteTo"))
            {
                // We are in no relevant method.
                return;
            }
            if (info.Method.Name.Equals("WriteRawTag"))
            {
                // Used to write tag information.
                return;
            }
            // Name of the type of the proto equivalent of the property.
            var type = info.Method.Name.Substring(5);
            // Name of the property
            var propName = info.Arguments[1].ToString();

            propName = propName.Substring(propName.IndexOf("get_") + 4);
            // Cut of parenthesis.
            propName = propName.Substring(0, propName.Length - 2);

            // Locate property from property list
            var property = properties.First(p => p.Name.Equals(propName));

            // Get more specific type.
            var specificType = InspectorTools.LiteralTypeMapper(type);

            property.Type = specificType;

            // Label and fieldTag are already set!
        }
示例#2
0
        // Read out static constructor for setters off _repeated_XXX_codec fields.
        public static void StaticCctorOnStore(StoreInfo info, List <IRClassProperty> properties,
                                              List <ulong> recordedTags)
        {
            if (!info.Field.Name.StartsWith("_repeated_"))
            {
                return;
            }

            // Extract the property name of the field we are storing data into.
            var property = info.Field.Name.Substring(10);             // Cut off '_repeated_' from front

            property = property.Substring(0, property.Length - 6);    // Cut off '_codec' at the end
            // Uppercase first character of property name, because .. inconsistencies..
            property = Char.ToUpper(property[0]) + property.Substring(1);

            // Find property.
            IRClassProperty prop;
            var             propEnum = properties.Where(p => p.Name.Equals(property));

            if (propEnum.Any())
            {
                prop = propEnum.First();
            }
            else
            {
                // Inconsistency happened in naming the backing field for repeated properties.
                // Retry with a trimmed property name.
                prop = properties.First(p => p.Name.Trim('_').Equals(property));
            }
            // POP matching tag for this property
            var tag = recordedTags[0];

            recordedTags.RemoveAt(0);

            // Split tag into bytes.
            var bytes = new List <byte>();

            // Bytes must be gotten in Little endian format!
            // Only send in the minimum of bytes.
            for (int i = 0; i < sizeof(ulong); ++i)
            {
                // Shift bits by bytesize (8) and take last 8 bits.
                var b = (byte)((tag >> (8 * i)) & 0xff);
                // Push the result onto the byte list.
                bytes.Add(b);
                // If the MSB of this byte is 0, break the loop.
                // => this guarantees minimal written bytes.
                if (0 == (b & 0x80))
                {
                    break;
                }
            }
            // bytes contains the written tag, split per 8 bits, in little endian.

            // Check if the field is packed.
            prop.Options.IsPacked = InspectorTools.TagToPackedSpecifier(bytes, prop.Type);

            return;
        }
示例#3
0
        // Get all properties from the type we are analyzing.
        public static List <IRClassProperty> ExtractClassProperties(TypeDefinition _subjectClass,
                                                                    out List <TypeDefinition> references)
        {
            // Will contain all typedefinitions of types referenced by this class.
            references = new List <TypeDefinition>();

            // All properties for the given class definition.
            List <IRClassProperty> properties = new List <IRClassProperty>();

            // Property != field
            // Properties expose fields by providing a getter/setter.
            // The properties are public accessible data, and these are the things that map
            // to protobuffer files.
            foreach (var property in _subjectClass.Properties)
            {
                // Property must have a setter method, otherwise it wouldn't be related to ProtoBuffers schema.
                if (property.SetMethod == null)
                {
                    continue;
                }

                // Object which the current property references.
                TypeDefinition refDefinition;
                // Set of field (proto) options.
                IRClassProperty.ILPropertyOptions options = new IRClassProperty.ILPropertyOptions();
                // Default to invalid field.
                options.Label = FieldLabel.INVALID;
                // IR type of the property.
                PropertyTypeKind propType = InspectorTools.DefaultTypeMapper(property, out refDefinition);

                // IR object - reference placeholder for the IR Class.
                IRTypeNode irReference = null;
                if (propType == PropertyTypeKind.TYPE_REF)
                {
                    irReference = InspectorTools.ConstructIRType(refDefinition);
                    // Also save the reference typedefinition for the caller to process.
                    references.Add(refDefinition);
                }

                // Construct IR property and store.
                var prop = new IRClassProperty
                {
                    Name           = property.Name,
                    Type           = propType,
                    ReferencedType = irReference,
                    Options        = options,
                };
                properties.Add(prop);
            }

            return(properties);
        }
示例#4
0
        // Get all properties from the type we are analyzing.
        public static List <IRClassProperty> ExtractClassProperties(TypeDefinition _subjectClass,
                                                                    out List <TypeDefinition> references)
        {
            // Contains all references (TypeDefinitions) that are referenced by this class.
            references = new List <TypeDefinition>();

            // All properties for the given class.
            List <IRClassProperty> properties = new List <IRClassProperty>();

            // Propertye != field; see SilentOrbitInspector.ExtractClassproperties(..)
            foreach (var property in _subjectClass.Properties)
            {
                // Default to OPTIONAL label. The Google protobuffer compiler is written for
                // proto3 syntax, which does not allow REQUIRED.
                // Everything is implicitly OPTIONAL, but OPTIONAL fields who have the default value
                // will not be written onto the wire.
                // CARE MUST BE TAKEN to provide all necessary values when using these decompiled proto files.
                FieldLabel label = FieldLabel.OPTIONAL;

                // Each schema related property must have a set method, but repeated fields don't have
                // a set method. We must figure out if the property is lib related or schema related!
                if (property.SetMethod == null)
                {
                    // Repeated field have propertyType RepeatedField<X>.
                    if (property.PropertyType.Name.Contains("RepeatedField") == true &&
                        property.PropertyType.IsGenericInstance)
                    {
                        // This field must be analyzed.
                        label = FieldLabel.REPEATED;
                    }
                    else
                    {
                        continue;
                    }
                }

                // Object which the current property references.
                TypeDefinition refDefinition;
                // Field options (directly related to protobuf schema)
                IRClassProperty.ILPropertyOptions opts = new IRClassProperty.ILPropertyOptions();
                // Add label to the property options.
                opts.Label = label;

                // Fetch the IR type of the property. - Doesn't actually matter, the Serialize handler will overwrite this.
                PropertyTypeKind propType = InspectorTools.DefaultTypeMapper(property, out refDefinition);

                // Construct IR reference placeholder.
                IRTypeNode irReference = null;
                if (propType == PropertyTypeKind.TYPE_REF)
                {
                    irReference = InspectorTools.ConstructIRType(refDefinition);
                    // And save the reference TYPEDEFINITION for the caller to process.
                    references.Add(refDefinition);
                }

                // Fetch the fieldNumber for this property.
                var tag = ExtractFieldNumber(_subjectClass, property.Name);
                // Add it to the options.
                opts.PropertyOrder = tag;

                // Construct the IR property and store it.
                var prop = new IRClassProperty()
                {
                    Name           = property.Name,
                    Type           = propType,
                    ReferencedType = irReference,
                    Options        = opts,
                };
                properties.Add(prop);
            }

            return(properties);
        }
示例#5
0
        public static void SerializeOnCall(CallInfo info, List <string> property_names, List <FieldDefinition> allFields, List <IRClassProperty> properties, List <TypeDefinition> references)
        {
            if (!info.Method.Name.StartsWith("Write") || info.Method.Name.Equals("WriteUntil"))
            {
                // We are in no relevant method.
                return;
            }

            var fieldNameArg   = info.Arguments[2].ToString();
            var bracketIdx     = fieldNameArg.LastIndexOf("[");
            var bracketLastIdx = fieldNameArg.LastIndexOf("]");
            var fieldNameRef   = UInt32.Parse(fieldNameArg.Substring(bracketIdx + 1, bracketLastIdx - bracketIdx - 1));
            var fieldName      = property_names[(int)fieldNameRef];

            var type = info.Method.Name.Substring(5);

            var packedIdx = type.IndexOf("Packed");
            var isPacked  = false;

            if (packedIdx > -1)
            {
                Debug.Assert(packedIdx == 0);
                isPacked = true;
                type     = type.Substring(6);
            }

            var specificType = InspectorTools.LiteralTypeMapper(type);
            var fieldIdx     = (int)info.Arguments[1];

            var label = FieldLabel.REQUIRED;

            if (info.Conditions.Any(c => c.Lhs.Contains("get_Count")))
            {
                label = FieldLabel.REPEATED;
            }
            else if (info.Conditions.Any(c => c.Lhs.Contains("has")))
            {
                label = FieldLabel.OPTIONAL;
            }

            // Construct IR reference placeholder.
            IRTypeNode irReference = null;

            if (specificType == PropertyTypeKind.TYPE_REF)
            {
                TypeReference fieldReference;
                if (info.Method.IsGenericInstance)
                {
                    var method = info.Method as GenericInstanceMethod;
                    fieldReference = method.GenericArguments[0];
                }
                else
                {
                    // Find out definition from arguments
                    var cleanFieldName = fieldName.ToLower().Replace("_", "");
                    var fieldRef       = allFields.OrderBy(f => f.Name.Length).First(field => field.Name.ToLower().Contains(cleanFieldName));
                    fieldReference = fieldRef.FieldType;
                }

                if (label == FieldLabel.REPEATED && fieldReference.IsGenericInstance)
                {
                    var genericField = fieldReference as GenericInstanceType;
                    fieldReference = genericField.GenericArguments[0];
                }

                var fieldDefinition = fieldReference.Resolve();
                irReference = InspectorTools.ConstructIRType(fieldDefinition);

                Debug.Assert(!fieldDefinition.FullName.Equals("System.UInt32"));

                // And save the reference TYPEDEFINITION for the caller to process.
                references.Add(fieldDefinition);
            }

            var newProperty = new IRClassProperty()
            {
                Name           = fieldName,
                Type           = specificType,
                ReferencedType = irReference,
                Options        = new IRClassProperty.ILPropertyOptions()
                {
                    Label         = label,
                    PropertyOrder = fieldIdx,
                    IsPacked      = isPacked,
                }
            };

            properties.Add(newProperty);

            return;
        }
示例#6
0
        // A method was called by our inspected method. We use the collected information (our environment)
        // to extract information about the type (and fields).
        public static void SerializeOnCall(CallInfo info, List <byte> writtenBytes,
                                           List <IRClassProperty> properties)
        {
            if (info.Method.Name == "WriteByte")
            {
                int byteAmount = (int)info.Arguments[1];
                writtenBytes.Add((byte)byteAmount);
                return;
            }
            if (info.Arguments.Any(x => x.ToString().Contains("GetSerializedSize()")))
            {
                return;
            }
            if (!info.Method.Name.StartsWith("Write") && info.Method.Name != "Serialize")
            {
                return;
            }
            // !!! packed vs not packed:
            // bnet.protocol.channel_invitation.IncrementChannelCountResponse/reservation_tokens: *not* packed
            // PegasusGame.ChooseEntities/entities: *packed*
            // not packed = {{tag, data}, {tag, data}, ...}
            // packed = {tag, size, data}
            // repeated fixed fields are packed by default.
            //
            // not packed:
            //   call: ProtocolParser.WriteUInt64(arg0, V_0)
            //   conditions: arg1.get_ReservationTokens().get_Count() > 0, &V_1.MoveNext() == true
            //
            // packed:
            //   call: ProtocolParser.WriteUInt32(arg0, V_0) // size
            //   conditions: arg1.get_Entities().get_Count() > 0, &V_2.MoveNext() == false
            //   call: ProtocolParser.WriteUInt64(arg0, V_3) // datum
            //   conditions: arg1.get_Entities().get_Count() > 0, &V_2.MoveNext() == false, &V_4.MoveNext() == true
            var iterConds = info.Conditions.Where(x => x.Lhs.Contains("MoveNext"));
            var listConds = info.Conditions.Where(x => x.Lhs.Contains("().get_Count()"));

            if (listConds.Any() && !iterConds.Any(x => x.Cmp == Comparison.IsTrue))
            {
                // Skip packed size writes:
                return;
            }

            // Get the packed flag.
            var packed = IsFieldPacked(iterConds);

            // Get the tag from the info.
            var tag = InspectorTools.GetFieldTag(writtenBytes);

            // Reset written bytes in order to process the next tag.
            writtenBytes.Clear();

            // Get the field label.
            var label = GetFieldLabel(info, iterConds);

            // Get the name for the current tag.
            var name = GetFieldName(info, label);

            // Fetch the property object by it's name
            var prop = properties.First(x => x.Name == name);

            // In case the writing class is called BinaryWriter, the mapping is different.
            if (info.Method.DeclaringType.Name.Equals("BinaryWriter"))
            {
                prop.Type = FixedTypeMapper(prop);
            }

            // Set property options
            prop.Options.Label         = label;
            prop.Options.PropertyOrder = tag;
            prop.Options.IsPacked      = packed;
            // Default value is extracted from the deserialize method..
        }