private void WriteMessage(IRClass c, TextWriter w, string prefix) { string reference = String.Format(_Reference, c.OriginalName); WriteComments(w, prefix, reference); // Type names are kept in PascalCase! w.WriteLine("{0}message {1} {{", prefix, c.ShortName); // Write all private types first! WritePrivateTypesToFile(c, w, prefix + "\t"); // Write all fields last! foreach (IRClassProperty prop in c.Properties.OrderBy(prop => prop.Options.PropertyOrder)) { IRClassProperty.ILPropertyOptions opts = prop.Options; string label = ProtoHelper.FieldLabelToString(opts.Label, false); string type = ProtoHelper.TypeTostring(prop.Type, c, prop.ReferencedType); string tag = opts.PropertyOrder.ToString(); string defaultValue = ""; if (prop.Options.DefaultValue != null) { string formattedValue = ProtoHelper.DefaultValueToString(prop.Options.DefaultValue, prop.ReferencedType); defaultValue = String.Format("[default = {0}]", formattedValue); } // Proto2 has repeated fields NOT PACKED by default, if they are // we mark that explicitly. string packed = ""; if (opts.IsPacked == true && opts.Label == FieldLabel.REPEATED) { packed = "[packed=true]"; } string propName = prop.Name.PascalToSnake(); if (packed.Length > 0 || defaultValue.Length > 0) { tag = tag.SuffixAlign(); } if (packed.Length > 0) { defaultValue = defaultValue.SuffixAlign(); } w.WriteLine("{0}{1}{2}{3} = {4}{5}{6};", prefix + "\t", label.SuffixAlign(), type.SuffixAlign(), propName, tag, defaultValue, packed); } // End message. w.WriteLine("{0}}}", prefix); w.WriteLine(); }
// 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); }
private void WriteMessage(IRClass c, TextWriter w, string prefix) { string reference = String.Format(_Reference, c.OriginalName); WriteComments(w, prefix, reference); // Type names are kept in PascalCase! w.WriteLine("{0}message {1} {{", prefix, c.ShortName); // Write all private types first! WritePrivateTypesToFile(c, w, prefix + "\t"); // Write all fields last! foreach (IRClassProperty prop in c.Properties.OrderBy(prop => prop.Options.PropertyOrder)) { IRClassProperty.ILPropertyOptions opts = prop.Options; // Proto3 syntax has implicit default values! string label = ProtoHelper.FieldLabelToString(opts.Label, true); string type = ProtoHelper.TypeTostring(prop.Type, c, prop.ReferencedType); string tag = opts.PropertyOrder.ToString(); // In proto3, the default for a repeated field is PACKED=TRUE. // Only if it's not packed.. we set it to false. string packed = ""; if (opts.IsPacked == false && opts.Label == FieldLabel.REPEATED) { packed = "[packed=false]"; } string propName = prop.Name.PascalToSnake(); if (packed.Length > 0) { tag = tag.SuffixAlign(); } w.WriteLine("{0}{1}{2}{3} = {4}{5};", prefix + "\t", label.SuffixAlign(), type.SuffixAlign(), propName, tag, packed); } // End message. w.WriteLine("{0}}}", prefix); w.WriteLine(); }
// 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); }