using System; using Google.ProtocolBuffers.DescriptorProtos; using Google.ProtocolBuffers.Descriptors; namespace Google.ProtocolBuffers.ProtoGen { /// /// Generator for the class describing the .proto file in general, /// containing things like the message descriptor. /// internal sealed class UmbrellaClassGenerator : SourceGeneratorBase, ISourceGenerator { internal UmbrellaClassGenerator(FileDescriptor descriptor) : base(descriptor) { } public void Generate(TextGenerator writer) { WriteIntroduction(writer); WriteDescriptor(writer); WriteChildren(writer, "Extensions", Descriptor.Extensions); writer.WriteLine("#region Static variables"); foreach (MessageDescriptor message in Descriptor.MessageTypes) { new MessageGenerator(message).GenerateStaticVariables(writer); } writer.WriteLine("#endregion"); // The class declaration either gets closed before or after the children are written. if (!DescriptorUtil.NestClasses(Descriptor)) { writer.Outdent(); writer.WriteLine("}"); } WriteChildren(writer, "Enums", Descriptor.EnumTypes); WriteChildren(writer, "Messages", Descriptor.MessageTypes); WriteChildren(writer, "Services", Descriptor.Services); if (DescriptorUtil.NestClasses(Descriptor)) { writer.Outdent(); writer.WriteLine("}"); } if (DescriptorUtil.GetNamespace(Descriptor) != "") { writer.Outdent(); writer.WriteLine("}"); } } private void WriteIntroduction(TextGenerator writer) { writer.WriteLine("// Generated by the protocol buffer compiler. DO NOT EDIT!"); writer.WriteLine(); Helpers.WriteNamespaces(writer); if (DescriptorUtil.GetNamespace(Descriptor) != "") { writer.WriteLine("namespace {0} {{", DescriptorUtil.GetNamespace(Descriptor)); writer.Indent(); writer.WriteLine(); } writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel, DescriptorUtil.GetUmbrellaClassName(Descriptor)); writer.WriteLine(); writer.Indent(); } private void WriteDescriptor(TextGenerator writer) { writer.WriteLine("#region Descriptor"); writer.WriteLine("public static pbd::FileDescriptor Descriptor {"); writer.WriteLine(" get { return descriptor; }"); writer.WriteLine("}"); writer.WriteLine("private static readonly pbd::FileDescriptor descriptor = pbd::FileDescriptor.InternalBuildGeneratedFileFrom("); writer.WriteLine(" global::System.Convert.FromBase64String("); writer.Indent(); writer.Indent(); // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64. byte[] bytes = Descriptor.Proto.ToByteArray(); string base64 = Convert.ToBase64String(bytes); while (base64.Length > 60) { writer.WriteLine("\"{0}\" + ", base64.Substring(0, 60)); base64 = base64.Substring(60); } writer.WriteLine("\"{0}\"),", base64); writer.WriteLine("new pbd::FileDescriptor[] {"); foreach (FileDescriptor dependency in Descriptor.Dependencies) { // TODO(jonskeet): The normal code won't work for the bootstrapping descriptor, because we don't get unknown fields :( if (dependency.Package == "google.protobuf" && dependency.Name.EndsWith("descriptor.proto")) { writer.WriteLine(" global::" + typeof(DescriptorProtoFile).FullName + ".Descriptor, "); continue; } writer.WriteLine(" {0}.Descriptor, ", DescriptorUtil.GetFullUmbrellaClassName(dependency)); } writer.WriteLine("});"); writer.Outdent(); writer.Outdent(); writer.WriteLine("#endregion"); writer.WriteLine(); } } }