private void DoParseFile(ProtoInputData inputData) { var sb = new StringBuilder(); DumpFileDescriptor(inputData, sb); outputProtoDefs.Add(new ProtoOutputData { file = inputData.proto, buffer = sb }); ProtoList.Add(inputData.proto.name); }
private bool ShouldDeferProto(ProtoInputData inputData) { foreach (var dependency in inputData.proto.dependency) { if (!dependency.StartsWith("google", StringComparison.Ordinal) && !ProtoList.Contains(dependency)) { return(true); } } return(false); }
private bool HandleProto(string name, byte[] data) { Console.Write("{0}... ", name); var inputData = new ProtoInputData(); if (Environment.GetCommandLineArgs().Contains("-dump", StringComparer.OrdinalIgnoreCase)) { var fileName = Path.Combine(OutputDir, $"{name}.dump"); Directory.CreateDirectory(Path.GetDirectoryName(fileName)); Console.WriteLine(" ! Dumping to '{0}'!", fileName); try { File.WriteAllBytes(fileName, data); } catch (Exception ex) { Console.WriteLine("Unable to dump: {0}", ex.Message); } } try { using (var ms = new MemoryStream(data)) inputData.proto = Serializer.Deserialize <FileDescriptorProto>(ms); } catch (EndOfStreamException ex) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("needs rescan: {0}", ex.Message); Console.ResetColor(); return(false); } catch (Exception ex) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("is invalid: {0}", ex.Message); Console.ResetColor(); return(true); } inputProtoDefs.Add(inputData); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("OK!"); Console.ResetColor(); return(true); }
// because of protobuf-net we're limited to parsing simple types at run-time as we can't parse the protobuf, but options shouldn't be too complex private void BuildExtension(string key, IEnumerable <FieldDescriptorProto> fields, ProtoInputData protoData) { var name = $"{key}Ext{Guid.NewGuid()}"; var extension = moduleBuilder.DefineType(name, TypeAttributes.Class); var pcType = typeof(ProtoContractAttribute); var pcCtor = pcType.GetConstructor(Type.EmptyTypes); var pcBuilder = new CustomAttributeBuilder(pcCtor, Type.EmptyTypes); extension.SetCustomAttribute(pcBuilder); foreach (var field in fields) { var fieldType = LookupBasicType(field.type, out var format, out var buildEnumProxy); var fbuilder = extension.DefineField(field.name, fieldType, FieldAttributes.Public); object defaultValue = field.default_value; if (field.type == FieldDescriptorProto.Type.TYPE_ENUM) { defaultValue = 0; } else if (string.IsNullOrEmpty(field.default_value)) { if (field.type == FieldDescriptorProto.Type.TYPE_STRING) { defaultValue = ""; } else { defaultValue = Activator.CreateInstance(fieldType); } } else { try { defaultValue = Convert.ChangeType(field.default_value, fieldType); } catch (FormatException) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Constructor for extension had bad format: {0}", key); Console.ResetColor(); return; } } if (buildEnumProxy) { var epType = typeof(EnumProxyAttribute); var epCtor = epType.GetConstructor(new[] { typeof(object), typeof(string) }); var epBuilder = new CustomAttributeBuilder(epCtor, new object[] { field.default_value, field.type_name }); fbuilder.SetCustomAttribute(epBuilder); } var dvType = typeof(DefaultValueAttribute); var dvCtor = dvType.GetConstructor(new[] { typeof(object) }); var dvBuilder = new CustomAttributeBuilder(dvCtor, new[] { defaultValue }); fbuilder.SetCustomAttribute(dvBuilder); var pmType = typeof(ProtoMemberAttribute); var pmCtor = pmType.GetConstructor(new[] { typeof(int) }); var pmBuilder = new CustomAttributeBuilder(pmCtor, new object[] { field.number }, new[] { pmType.GetProperty("Name"), pmType.GetProperty("DataFormat") }, new object[] { $"({field.name})", format }); fbuilder.SetCustomAttribute(pmBuilder); } var extensionType = extension.CreateType(); if (!protoData.extensions.ContainsKey(key)) { protoData.extensions[key] = new List <Type>(); } protoData.extensions[key].Add(extensionType); // Update extensions known by protodefs that rely on us foreach (var dependent in inputProtoDefs.Where(x => x.proto.dependency.Contains(protoData.proto.name))) { if (!dependent.extensions.ContainsKey(key)) { dependent.extensions[key] = new List <Type>(); } dependent.extensions[key].Add(extensionType); } }
private void DumpDescriptor(DescriptorProto proto, ProtoInputData inputData, StringBuilder sb, int level) { PushDescriptorName(proto); var levelspace = new string('\t', level); sb.AppendLine($"{levelspace}message {proto.name} {{"); foreach (var option in DumpOptions(proto.options, inputData.extensions)) { sb.AppendLine($"{levelspace}\toption {option.Key} = {option.Value};"); } foreach (var field in proto.nested_type) { DumpDescriptor(field, inputData, sb, level + 1); } DumpExtensionDescriptor(proto.extension, inputData, sb, $"{levelspace}\t"); foreach (var field in proto.enum_type) { DumpEnumDescriptor(field, inputData.extensions, sb, level + 1); } foreach (var field in proto.field.Where(x => !x.oneof_indexSpecified)) { var enumLookup = new List <EnumDescriptorProto>(); enumLookup.AddRange(inputData.proto.enum_type); // add global enums enumLookup.AddRange(proto.enum_type); // add this message's nested enums sb.AppendLine($"{levelspace}\t{BuildDescriptorDeclaration(field, inputData.extensions)}"); } for (var i = 0; i < proto.oneof_decl.Count; i++) { var oneof = proto.oneof_decl[i]; var fields = proto.field.Where(x => x.oneof_indexSpecified && x.oneof_index == i).ToArray(); sb.AppendLine($"{levelspace}\toneof {oneof.name} {{"); foreach (var field in fields) { sb.AppendLine($"{levelspace}\t\t{BuildDescriptorDeclaration(field, inputData.extensions, emitFieldLabel: false)}"); } sb.AppendLine($"{levelspace}\t}}"); } if (proto.extension_range.Count > 0) { sb.AppendLine(); } foreach (var range in proto.extension_range) { var max = Convert.ToString(range.end); // http://code.google.com/apis/protocolbuffers/docs/proto.html#extensions // If your numbering convention might involve extensions having very large numbers as tags, you can specify // that your extension range goes up to the maximum possible field number using the max keyword: // max is 2^29 - 1, or 536,870,911. if (range.end >= 536870911) { max = "max"; } sb.AppendLine($"{levelspace}\textensions {range.start} to {max};"); } sb.AppendLine($"{levelspace}}}"); sb.AppendLine(); PopDescriptorName(); }
private void DumpFileDescriptor(ProtoInputData inputData, StringBuilder sb) { if (!string.IsNullOrEmpty(inputData.proto.package)) { PushDescriptorName(inputData.proto); } var marker = false; foreach (var dependency in inputData.proto.dependency) { sb.AppendLine($"import \"{dependency}\";"); marker = true; } if (marker) { sb.AppendLine(); marker = false; } if (!string.IsNullOrEmpty(inputData.proto.package)) { sb.AppendLine($"package {inputData.proto.package};"); marker = true; } if (marker) { sb.AppendLine(); marker = false; } foreach (var option in DumpOptions(inputData.proto.options, inputData.extensions)) { sb.AppendLine($"option {option.Key} = {option.Value};"); marker = true; } if (marker) { sb.AppendLine(); } DumpExtensionDescriptor(inputData.proto.extension, inputData, sb, string.Empty); foreach (var field in inputData.proto.enum_type) { DumpEnumDescriptor(field, inputData.extensions, sb, 0); } foreach (var proto in inputData.proto.message_type) { DumpDescriptor(proto, inputData, sb, 0); } foreach (var service in inputData.proto.service) { sb.AppendLine($"service {service.name} {{"); foreach (var option in DumpOptions(service.options, inputData.extensions)) { sb.AppendLine($"\toption {option.Key} = {option.Value};"); } foreach (var method in service.method) { var declaration = $"\trpc {method.name} ({method.input_type}) returns ({method.output_type})"; var options = DumpOptions(method.options, inputData.extensions); var parameters = string.Empty; if (options.Count == 0) { sb.AppendLine($"{declaration};"); } else { sb.AppendLine($"{declaration} {{"); foreach (var option in options) { sb.AppendLine($"\t\toption {option.Key} = {option.Value};"); } sb.AppendLine("\t}"); } } sb.AppendLine("}"); } if (!string.IsNullOrEmpty(inputData.proto.package)) { PopDescriptorName(); } }
private void DumpExtensionDescriptor(IEnumerable <FieldDescriptorProto> fields, ProtoInputData inputData, StringBuilder sb, string levelspace) { foreach (var mapping in fields.GroupBy(x => x.extendee)) { if (string.IsNullOrEmpty(mapping.Key)) { throw new Exception("Empty extendee in extension, this should not be possible"); } if (mapping.Key.StartsWith(".google.protobuf", StringComparison.Ordinal)) { BuildExtension(mapping.Key.Substring(1), mapping.ToArray(), inputData); } sb.AppendLine($"{levelspace}extend {mapping.Key} {{"); foreach (var field in mapping) { sb.AppendLine($"{levelspace}\t{BuildDescriptorDeclaration(field, inputData.extensions)}"); } sb.AppendLine($"{levelspace}}}"); sb.AppendLine(); } }