aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/ProtoGen
diff options
context:
space:
mode:
Diffstat (limited to 'csharp/src/ProtoGen')
-rw-r--r--csharp/src/ProtoGen/DependencyResolutionException.cs55
-rw-r--r--csharp/src/ProtoGen/DescriptorUtil.cs106
-rw-r--r--csharp/src/ProtoGen/EnumFieldGenerator.cs148
-rw-r--r--csharp/src/ProtoGen/EnumGenerator.cs62
-rw-r--r--csharp/src/ProtoGen/ExtensionGenerator.cs183
-rw-r--r--csharp/src/ProtoGen/FieldGeneratorBase.cs389
-rw-r--r--csharp/src/ProtoGen/Generator.cs267
-rw-r--r--csharp/src/ProtoGen/GeneratorOptions.cs330
-rw-r--r--csharp/src/ProtoGen/Helpers.cs45
-rw-r--r--csharp/src/ProtoGen/IFieldSourceGenerator.cs53
-rw-r--r--csharp/src/ProtoGen/ISourceGenerator.cs43
-rw-r--r--csharp/src/ProtoGen/InvalidOptionsException.cs77
-rw-r--r--csharp/src/ProtoGen/MessageFieldGenerator.cs174
-rw-r--r--csharp/src/ProtoGen/MessageGenerator.cs893
-rw-r--r--csharp/src/ProtoGen/PluginProtoFile.cs1187
-rw-r--r--csharp/src/ProtoGen/PrimitiveFieldGenerator.cs140
-rw-r--r--csharp/src/ProtoGen/Program.cs105
-rw-r--r--csharp/src/ProtoGen/ProgramPreprocess.cs276
-rw-r--r--csharp/src/ProtoGen/Properties/AssemblyInfo.cs29
-rw-r--r--csharp/src/ProtoGen/ProtoGen.csproj98
-rw-r--r--csharp/src/ProtoGen/ProtocGenCs.cs76
-rw-r--r--csharp/src/ProtoGen/RepeatedEnumFieldGenerator.cs212
-rw-r--r--csharp/src/ProtoGen/RepeatedMessageFieldGenerator.cs184
-rw-r--r--csharp/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs207
-rw-r--r--csharp/src/ProtoGen/ServiceGenerator.cs190
-rw-r--r--csharp/src/ProtoGen/ServiceInterfaceGenerator.cs300
-rw-r--r--csharp/src/ProtoGen/SourceGeneratorBase.cs167
-rw-r--r--csharp/src/ProtoGen/SourceGenerators.cs87
-rw-r--r--csharp/src/ProtoGen/UmbrellaClassGenerator.cs294
-rw-r--r--csharp/src/ProtoGen/app.config7
-rw-r--r--csharp/src/ProtoGen/protoc-gen-cs.csproj101
31 files changed, 6485 insertions, 0 deletions
diff --git a/csharp/src/ProtoGen/DependencyResolutionException.cs b/csharp/src/ProtoGen/DependencyResolutionException.cs
new file mode 100644
index 00000000..aef192e0
--- /dev/null
+++ b/csharp/src/ProtoGen/DependencyResolutionException.cs
@@ -0,0 +1,55 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// Exception thrown when dependencies within a descriptor set can't be resolved.
+ /// </summary>
+ public sealed class DependencyResolutionException : Exception
+ {
+ public DependencyResolutionException(string message) : base(message)
+ {
+ }
+
+ public DependencyResolutionException(string format, params object[] args)
+ : base(string.Format(format, args))
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/DescriptorUtil.cs b/csharp/src/ProtoGen/DescriptorUtil.cs
new file mode 100644
index 00000000..0666bb93
--- /dev/null
+++ b/csharp/src/ProtoGen/DescriptorUtil.cs
@@ -0,0 +1,106 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// Utility class for determining namespaces etc.
+ /// </summary>
+ internal static class DescriptorUtil
+ {
+ internal static string GetFullUmbrellaClassName(IDescriptor descriptor)
+ {
+ CSharpFileOptions options = descriptor.File.CSharpOptions;
+ string result = options.Namespace;
+ if (result != "")
+ {
+ result += '.';
+ }
+ result += GetQualifiedUmbrellaClassName(options);
+ return "global::" + result;
+ }
+
+ /// <summary>
+ /// Evaluates the options and returns the qualified name of the umbrella class
+ /// relative to the descriptor type's namespace. Basically concatenates the
+ /// UmbrellaNamespace + UmbrellaClassname fields.
+ /// </summary>
+ internal static string GetQualifiedUmbrellaClassName(CSharpFileOptions options)
+ {
+ string fullName = options.UmbrellaClassname;
+ if (!options.NestClasses && options.UmbrellaNamespace != "")
+ {
+ fullName = String.Format("{0}.{1}", options.UmbrellaNamespace, options.UmbrellaClassname);
+ }
+ return fullName;
+ }
+
+ internal static string GetMappedTypeName(MappedType type)
+ {
+ switch (type)
+ {
+ case MappedType.Int32:
+ return "int";
+ case MappedType.Int64:
+ return "long";
+ case MappedType.UInt32:
+ return "uint";
+ case MappedType.UInt64:
+ return "ulong";
+ case MappedType.Single:
+ return "float";
+ case MappedType.Double:
+ return "double";
+ case MappedType.Boolean:
+ return "bool";
+ case MappedType.String:
+ return "string";
+ case MappedType.ByteString:
+ return "pb::ByteString";
+ case MappedType.Enum:
+ return null;
+ case MappedType.Message:
+ return null;
+ default:
+ throw new ArgumentOutOfRangeException("Unknown mapped type " + type);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/EnumFieldGenerator.cs b/csharp/src/ProtoGen/EnumFieldGenerator.cs
new file mode 100644
index 00000000..8d70bc67
--- /dev/null
+++ b/csharp/src/ProtoGen/EnumFieldGenerator.cs
@@ -0,0 +1,148 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class EnumFieldGenerator : FieldGeneratorBase, IFieldSourceGenerator
+ {
+ internal EnumFieldGenerator(FieldDescriptor descriptor, int fieldOrdinal)
+ : base(descriptor, fieldOrdinal)
+ {
+ }
+
+ public void GenerateMembers(TextGenerator writer)
+ {
+ writer.WriteLine("private bool has{0};", PropertyName);
+ writer.WriteLine("private {0} {1}_ = {2};", TypeName, Name, DefaultValue);
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public bool Has{0} {{", PropertyName);
+ writer.WriteLine(" get {{ return has{0}; }}", PropertyName);
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return {0}_; }}", Name);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuilderMembers(TextGenerator writer)
+ {
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public bool Has{0} {{", PropertyName);
+ writer.WriteLine(" get {{ return result.has{0}; }}", PropertyName);
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return result.{0}; }}", PropertyName);
+ writer.WriteLine(" set {{ Set{0}(value); }}", PropertyName);
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.has{0} = true;", PropertyName);
+ writer.WriteLine(" result.{0}_ = value;", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.has{0} = false;", PropertyName);
+ writer.WriteLine(" result.{0}_ = {1};", Name, DefaultValue);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ }
+
+ public void GenerateMergingCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (other.Has{0}) {{", PropertyName);
+ writer.WriteLine(" {0} = other.{0};", PropertyName);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuildingCode(TextGenerator writer)
+ {
+ // Nothing to do here for enum types
+ }
+
+ public void GenerateParsingCode(TextGenerator writer)
+ {
+ writer.WriteLine("object unknown;");
+ writer.WriteLine("if(input.ReadEnum(ref result.{0}_, out unknown)) {{", Name);
+ writer.WriteLine(" result.has{0} = true;", PropertyName);
+ writer.WriteLine("} else if(unknown is int) {");
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now
+ writer.WriteLine(" unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);");
+ writer.WriteLine(" }");
+ writer.WriteLine(" unknownFields.MergeVarintField({0}, (ulong)(int)unknown);", Number);
+ }
+ writer.WriteLine("}");
+ }
+
+ public void GenerateSerializationCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) {{", PropertyName);
+ writer.WriteLine(" output.WriteEnum({0}, field_names[{2}], (int) {1}, {1});", Number, PropertyName,
+ FieldOrdinal);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateSerializedSizeCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) {{", PropertyName);
+ writer.WriteLine(" size += pb::CodedOutputStream.ComputeEnumSize({0}, (int) {1});", Number, PropertyName);
+ writer.WriteLine("}");
+ }
+
+ public override void WriteHash(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) hash ^= {1}_.GetHashCode();", PropertyName, Name);
+ }
+
+ public override void WriteEquals(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0} != other.has{0} || (has{0} && !{1}_.Equals(other.{1}_))) return false;",
+ PropertyName, Name);
+ }
+
+ public override void WriteToString(TextGenerator writer)
+ {
+ writer.WriteLine("PrintField(\"{0}\", has{1}, {2}_, writer);", Descriptor.Name, PropertyName, Name);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/EnumGenerator.cs b/csharp/src/ProtoGen/EnumGenerator.cs
new file mode 100644
index 00000000..a6ed45d1
--- /dev/null
+++ b/csharp/src/ProtoGen/EnumGenerator.cs
@@ -0,0 +1,62 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class EnumGenerator : SourceGeneratorBase<EnumDescriptor>, ISourceGenerator
+ {
+ internal EnumGenerator(EnumDescriptor descriptor) : base(descriptor)
+ {
+ }
+
+ // TODO(jonskeet): Write out enum descriptors? Can be retrieved from file...
+ public void Generate(TextGenerator writer)
+ {
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("{0} enum {1} {{", ClassAccessLevel, Descriptor.Name);
+ writer.Indent();
+ foreach (EnumValueDescriptor value in Descriptor.Values)
+ {
+ writer.WriteLine("{0} = {1},", value.Name, value.Number);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/ExtensionGenerator.cs b/csharp/src/ProtoGen/ExtensionGenerator.cs
new file mode 100644
index 00000000..a862a7a0
--- /dev/null
+++ b/csharp/src/ProtoGen/ExtensionGenerator.cs
@@ -0,0 +1,183 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class ExtensionGenerator : FieldGeneratorBase, ISourceGenerator
+ {
+ private readonly string extends;
+ private readonly string scope;
+ private readonly string type;
+ private readonly string name;
+
+ internal ExtensionGenerator(FieldDescriptor descriptor)
+ : base(descriptor, 0)
+ {
+ if (Descriptor.ExtensionScope != null)
+ {
+ scope = GetClassName(Descriptor.ExtensionScope);
+ }
+ else
+ {
+ scope = DescriptorUtil.GetFullUmbrellaClassName(Descriptor.File);
+ }
+ switch (Descriptor.MappedType)
+ {
+ case MappedType.Message:
+ type = GetClassName(Descriptor.MessageType);
+ break;
+ case MappedType.Enum:
+ type = GetClassName(Descriptor.EnumType);
+ break;
+ default:
+ type = DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
+ break;
+ }
+ extends = GetClassName(Descriptor.ContainingType);
+ name = Descriptor.CSharpOptions.PropertyName;
+ }
+
+ public void Generate(TextGenerator writer)
+ {
+ if (Descriptor.File.CSharpOptions.ClsCompliance && GetFieldConstantName(Descriptor).StartsWith("_"))
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+
+ writer.WriteLine("public const int {0} = {1};", GetFieldConstantName(Descriptor), Descriptor.FieldNumber);
+
+ if (UseLiteRuntime)
+ {
+ if (Descriptor.MappedType == MappedType.Message && Descriptor.MessageType.Options.MessageSetWireFormat)
+ {
+ throw new ArgumentException(
+ "option message_set_wire_format = true; is not supported in Lite runtime extensions.");
+ }
+ if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance)
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+ writer.WriteLine("{0} static pb::{4}<{1}, {2}> {3};", ClassAccessLevel, extends, type, name,
+ Descriptor.IsRepeated ? "GeneratedRepeatExtensionLite" : "GeneratedExtensionLite");
+ }
+ else if (Descriptor.IsRepeated)
+ {
+ if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance)
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+ writer.WriteLine("{0} static pb::GeneratedExtensionBase<scg::IList<{1}>> {2};", ClassAccessLevel, type,
+ name);
+ }
+ else
+ {
+ if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance)
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+ writer.WriteLine("{0} static pb::GeneratedExtensionBase<{1}> {2};", ClassAccessLevel, type, name);
+ }
+ }
+
+ internal void GenerateStaticVariableInitializers(TextGenerator writer)
+ {
+ if (UseLiteRuntime)
+ {
+ writer.WriteLine("{0}.{1} = ", scope, name);
+ writer.Indent();
+ writer.WriteLine("new pb::{0}<{1}, {2}>(",
+ Descriptor.IsRepeated ? "GeneratedRepeatExtensionLite" : "GeneratedExtensionLite",
+ extends, type);
+ writer.Indent();
+ writer.WriteLine("\"{0}\",", Descriptor.FullName);
+ writer.WriteLine("{0}.DefaultInstance,", extends);
+ if (!Descriptor.IsRepeated)
+ {
+ writer.WriteLine("{0},",
+ Descriptor.HasDefaultValue
+ ? DefaultValue
+ : IsNullableType ? "null" : "default(" + type + ")");
+ }
+ writer.WriteLine("{0},",
+ (Descriptor.MappedType == MappedType.Message) ? type + ".DefaultInstance" : "null");
+ writer.WriteLine("{0},",
+ (Descriptor.MappedType == MappedType.Enum) ? "new EnumLiteMap<" + type + ">()" : "null");
+ writer.WriteLine("{0}.{1}FieldNumber,", scope, name);
+ writer.Write("pbd::FieldType.{0}", Descriptor.FieldType);
+ if (Descriptor.IsRepeated)
+ {
+ writer.WriteLine(",");
+ writer.Write(Descriptor.IsPacked ? "true" : "false");
+ }
+ writer.Outdent();
+ writer.WriteLine(");");
+ writer.Outdent();
+ }
+ else if (Descriptor.IsRepeated)
+ {
+ writer.WriteLine(
+ "{0}.{1} = pb::GeneratedRepeatExtension<{2}>.CreateInstance({0}.Descriptor.Extensions[{3}]);", scope,
+ name, type, Descriptor.Index);
+ }
+ else
+ {
+ writer.WriteLine(
+ "{0}.{1} = pb::GeneratedSingleExtension<{2}>.CreateInstance({0}.Descriptor.Extensions[{3}]);", scope,
+ name, type, Descriptor.Index);
+ }
+ }
+
+ internal void GenerateExtensionRegistrationCode(TextGenerator writer)
+ {
+ writer.WriteLine("registry.Add({0}.{1});", scope, name);
+ }
+
+ public override void WriteHash(TextGenerator writer)
+ {
+ }
+
+ public override void WriteEquals(TextGenerator writer)
+ {
+ }
+
+ public override void WriteToString(TextGenerator writer)
+ {
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/FieldGeneratorBase.cs b/csharp/src/ProtoGen/FieldGeneratorBase.cs
new file mode 100644
index 00000000..93aee6ca
--- /dev/null
+++ b/csharp/src/ProtoGen/FieldGeneratorBase.cs
@@ -0,0 +1,389 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Globalization;
+using System.Text;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal abstract class FieldGeneratorBase : SourceGeneratorBase<FieldDescriptor>
+ {
+ private readonly int _fieldOrdinal;
+
+ protected FieldGeneratorBase(FieldDescriptor descriptor, int fieldOrdinal)
+ : base(descriptor)
+ {
+ _fieldOrdinal = fieldOrdinal;
+ }
+
+ public abstract void WriteHash(TextGenerator writer);
+ public abstract void WriteEquals(TextGenerator writer);
+ public abstract void WriteToString(TextGenerator writer);
+
+ public int FieldOrdinal
+ {
+ get { return _fieldOrdinal; }
+ }
+
+ private static bool AllPrintableAscii(string text)
+ {
+ foreach (char c in text)
+ {
+ if (c < 0x20 || c > 0x7e)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// This returns true if the field has a non-default default value. For instance this returns
+ /// false for numerics with a default of zero '0', or booleans with a default of false.
+ /// </summary>
+ protected bool HasDefaultValue
+ {
+ get
+ {
+ switch (Descriptor.FieldType)
+ {
+ case FieldType.Float:
+ case FieldType.Double:
+ case FieldType.Int32:
+ case FieldType.Int64:
+ case FieldType.SInt32:
+ case FieldType.SInt64:
+ case FieldType.SFixed32:
+ case FieldType.SFixed64:
+ case FieldType.UInt32:
+ case FieldType.UInt64:
+ case FieldType.Fixed32:
+ case FieldType.Fixed64:
+ {
+ IConvertible value = (IConvertible) Descriptor.DefaultValue;
+ return value.ToString(CultureInfo.InvariantCulture) != "0";
+ }
+ case FieldType.Bool:
+ return ((bool) Descriptor.DefaultValue) == true;
+ default:
+ return true;
+ }
+ }
+ }
+
+ /// <remarks>Copy exists in ExtensionGenerator.cs</remarks>
+ protected string DefaultValue
+ {
+ get
+ {
+ string suffix = "";
+ switch (Descriptor.FieldType)
+ {
+ case FieldType.Float:
+ suffix = "F";
+ break;
+ case FieldType.Double:
+ suffix = "D";
+ break;
+ case FieldType.Int64:
+ suffix = "L";
+ break;
+ case FieldType.UInt64:
+ suffix = "UL";
+ break;
+ }
+ switch (Descriptor.FieldType)
+ {
+ case FieldType.Float:
+ case FieldType.Double:
+ case FieldType.Int32:
+ case FieldType.Int64:
+ case FieldType.SInt32:
+ case FieldType.SInt64:
+ case FieldType.SFixed32:
+ case FieldType.SFixed64:
+ case FieldType.UInt32:
+ case FieldType.UInt64:
+ case FieldType.Fixed32:
+ case FieldType.Fixed64:
+ {
+ // The simple Object.ToString converts using the current culture.
+ // We want to always use the invariant culture so it's predictable.
+ IConvertible value = (IConvertible) Descriptor.DefaultValue;
+ //a few things that must be handled explicitly
+ if (Descriptor.FieldType == FieldType.Double && value is double)
+ {
+ if (double.IsNaN((double) value))
+ {
+ return "double.NaN";
+ }
+ if (double.IsPositiveInfinity((double) value))
+ {
+ return "double.PositiveInfinity";
+ }
+ if (double.IsNegativeInfinity((double) value))
+ {
+ return "double.NegativeInfinity";
+ }
+ }
+ else if (Descriptor.FieldType == FieldType.Float && value is float)
+ {
+ if (float.IsNaN((float) value))
+ {
+ return "float.NaN";
+ }
+ if (float.IsPositiveInfinity((float) value))
+ {
+ return "float.PositiveInfinity";
+ }
+ if (float.IsNegativeInfinity((float) value))
+ {
+ return "float.NegativeInfinity";
+ }
+ }
+ return value.ToString(CultureInfo.InvariantCulture) + suffix;
+ }
+ case FieldType.Bool:
+ return (bool) Descriptor.DefaultValue ? "true" : "false";
+
+ case FieldType.Bytes:
+ if (!Descriptor.HasDefaultValue)
+ {
+ return "pb::ByteString.Empty";
+ }
+ if (UseLiteRuntime && Descriptor.DefaultValue is ByteString)
+ {
+ string temp = (((ByteString) Descriptor.DefaultValue).ToBase64());
+ return String.Format("pb::ByteString.FromBase64(\"{0}\")", temp);
+ }
+ return string.Format("(pb::ByteString) {0}.Descriptor.Fields[{1}].DefaultValue",
+ GetClassName(Descriptor.ContainingType), Descriptor.Index);
+ case FieldType.String:
+ if (AllPrintableAscii(Descriptor.Proto.DefaultValue))
+ {
+ // All chars are ASCII and printable. In this case we only
+ // need to escape quotes and backslashes.
+ return "\"" + Descriptor.Proto.DefaultValue
+ .Replace("\\", "\\\\")
+ .Replace("'", "\\'")
+ .Replace("\"", "\\\"")
+ + "\"";
+ }
+ if (UseLiteRuntime && Descriptor.DefaultValue is String)
+ {
+ string temp = Convert.ToBase64String(
+ Encoding.UTF8.GetBytes((String) Descriptor.DefaultValue));
+ return String.Format("pb::ByteString.FromBase64(\"{0}\").ToStringUtf8()", temp);
+ }
+ return string.Format("(string) {0}.Descriptor.Fields[{1}].DefaultValue",
+ GetClassName(Descriptor.ContainingType), Descriptor.Index);
+ case FieldType.Enum:
+ return TypeName + "." + ((EnumValueDescriptor) Descriptor.DefaultValue).Name;
+ case FieldType.Message:
+ case FieldType.Group:
+ return TypeName + ".DefaultInstance";
+ default:
+ throw new InvalidOperationException("Invalid field descriptor type");
+ }
+ }
+ }
+
+ protected string PropertyName
+ {
+ get { return Descriptor.CSharpOptions.PropertyName; }
+ }
+
+ protected string Name
+ {
+ get { return NameHelpers.UnderscoresToCamelCase(GetFieldName(Descriptor)); }
+ }
+
+ protected int Number
+ {
+ get { return Descriptor.FieldNumber; }
+ }
+
+ protected void AddNullCheck(TextGenerator writer)
+ {
+ AddNullCheck(writer, "value");
+ }
+
+ protected void AddNullCheck(TextGenerator writer, string name)
+ {
+ if (IsNullableType)
+ {
+ writer.WriteLine(" pb::ThrowHelper.ThrowIfNull({0}, \"{0}\");", name);
+ }
+ }
+
+ protected void AddPublicMemberAttributes(TextGenerator writer)
+ {
+ AddDeprecatedFlag(writer);
+ AddClsComplianceCheck(writer);
+ }
+
+ protected void AddClsComplianceCheck(TextGenerator writer)
+ {
+ if (!Descriptor.IsCLSCompliant && Descriptor.File.CSharpOptions.ClsCompliance)
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+ }
+
+ protected bool IsObsolete { get { return Descriptor.Options.Deprecated; } }
+
+ /// <summary>
+ /// Writes [global::System.ObsoleteAttribute()] if the member is obsolete
+ /// </summary>
+ protected void AddDeprecatedFlag(TextGenerator writer)
+ {
+ if (IsObsolete)
+ {
+ writer.WriteLine("[global::System.ObsoleteAttribute()]");
+ }
+ }
+
+ /// <summary>
+ /// For encodings with fixed sizes, returns that size in bytes. Otherwise
+ /// returns -1. TODO(jonskeet): Make this less ugly.
+ /// </summary>
+ protected int FixedSize
+ {
+ get
+ {
+ switch (Descriptor.FieldType)
+ {
+ case FieldType.UInt32:
+ case FieldType.UInt64:
+ case FieldType.Int32:
+ case FieldType.Int64:
+ case FieldType.SInt32:
+ case FieldType.SInt64:
+ case FieldType.Enum:
+ case FieldType.Bytes:
+ case FieldType.String:
+ case FieldType.Message:
+ case FieldType.Group:
+ return -1;
+ case FieldType.Float:
+ return WireFormat.FloatSize;
+ case FieldType.SFixed32:
+ return WireFormat.SFixed32Size;
+ case FieldType.Fixed32:
+ return WireFormat.Fixed32Size;
+ case FieldType.Double:
+ return WireFormat.DoubleSize;
+ case FieldType.SFixed64:
+ return WireFormat.SFixed64Size;
+ case FieldType.Fixed64:
+ return WireFormat.Fixed64Size;
+ case FieldType.Bool:
+ return WireFormat.BoolSize;
+ default:
+ throw new InvalidOperationException("Invalid field descriptor type");
+ }
+ }
+ }
+
+ protected bool IsNullableType
+ {
+ get
+ {
+ switch (Descriptor.FieldType)
+ {
+ case FieldType.Float:
+ case FieldType.Double:
+ case FieldType.Int32:
+ case FieldType.Int64:
+ case FieldType.SInt32:
+ case FieldType.SInt64:
+ case FieldType.SFixed32:
+ case FieldType.SFixed64:
+ case FieldType.UInt32:
+ case FieldType.UInt64:
+ case FieldType.Fixed32:
+ case FieldType.Fixed64:
+ case FieldType.Bool:
+ case FieldType.Enum:
+ return false;
+ case FieldType.Bytes:
+ case FieldType.String:
+ case FieldType.Message:
+ case FieldType.Group:
+ return true;
+ default:
+ throw new InvalidOperationException("Invalid field descriptor type");
+ }
+ }
+ }
+
+ protected string TypeName
+ {
+ get
+ {
+ switch (Descriptor.FieldType)
+ {
+ case FieldType.Enum:
+ return GetClassName(Descriptor.EnumType);
+ case FieldType.Message:
+ case FieldType.Group:
+ return GetClassName(Descriptor.MessageType);
+ default:
+ return DescriptorUtil.GetMappedTypeName(Descriptor.MappedType);
+ }
+ }
+ }
+
+ protected string MessageOrGroup
+ {
+ get { return Descriptor.FieldType == FieldType.Group ? "Group" : "Message"; }
+ }
+
+ /// <summary>
+ /// Returns the type name as used in CodedInputStream method names: SFixed32, UInt32 etc.
+ /// </summary>
+ protected string CapitalizedTypeName
+ {
+ get
+ {
+ // Our enum names match perfectly. How serendipitous.
+ return Descriptor.FieldType.ToString();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/Generator.cs b/csharp/src/ProtoGen/Generator.cs
new file mode 100644
index 00000000..bc481ec0
--- /dev/null
+++ b/csharp/src/ProtoGen/Generator.cs
@@ -0,0 +1,267 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Google.ProtocolBuffers.Collections;
+using Google.ProtocolBuffers.Compiler.PluginProto;
+using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// Code generator for protocol buffers. Only C# is supported at the moment.
+ /// </summary>
+ public sealed class Generator
+ {
+ private readonly GeneratorOptions options;
+
+ private Generator(GeneratorOptions options)
+ {
+ options.Validate();
+ this.options = options;
+ }
+
+ /// <summary>
+ /// Returns a generator configured with the specified options.
+ /// </summary>
+ public static Generator CreateGenerator(GeneratorOptions options)
+ {
+ return new Generator(options);
+ }
+
+ public void Generate(CodeGeneratorRequest request, CodeGeneratorResponse.Builder response)
+ {
+ IList<FileDescriptor> descriptors = ConvertDescriptors(options.FileOptions, request.ProtoFileList);
+
+ // Combine with options from command line
+ foreach (FileDescriptor descriptor in descriptors)
+ {
+ descriptor.ConfigureWithDefaultOptions(options.FileOptions);
+ }
+
+ bool duplicates = false;
+ Dictionary<string, bool> names = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
+ foreach (FileDescriptor descriptor in descriptors)
+ {
+ string file = GetOutputFile(descriptor, false);
+ if (names.ContainsKey(file))
+ {
+ duplicates = true;
+ break;
+ }
+ names.Add(file, true);
+ }
+
+ //ROK - Changed to dictionary from HashSet to allow 2.0 compile
+ var filesToGenerate = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+ foreach (var item in request.FileToGenerateList)
+ {
+ filesToGenerate[item] = null;
+ }
+ foreach (FileDescriptor descriptor in descriptors)
+ {
+ // Optionally exclude descriptors in google.protobuf
+ if (descriptor.CSharpOptions.IgnoreGoogleProtobuf && descriptor.Package == "google.protobuf")
+ {
+ continue;
+ }
+ if (filesToGenerate.ContainsKey(descriptor.Name))
+ {
+ Generate(descriptor, duplicates, response);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Generates code for a particular file. All dependencies must
+ /// already have been resolved.
+ /// </summary>
+ private void Generate(FileDescriptor descriptor, bool duplicates, CodeGeneratorResponse.Builder response)
+ {
+ var code = new StringBuilder();
+ var ucg = new UmbrellaClassGenerator(descriptor);
+ using (StringWriter textWriter = new StringWriter(code))
+ {
+ TextGenerator writer = new TextGenerator(textWriter, options.LineBreak);
+ ucg.Generate(writer);
+ }
+ response.AddFile(new CodeGeneratorResponse.Types.File.Builder
+ {
+ Name = GetOutputFile(descriptor, duplicates),
+ Content = code.ToString(),
+ }.Build());
+ }
+
+ private string GetOutputFile(FileDescriptor descriptor, bool duplicates)
+ {
+ CSharpFileOptions fileOptions = descriptor.CSharpOptions;
+
+ string filename = descriptor.CSharpOptions.UmbrellaClassname + descriptor.CSharpOptions.FileExtension;
+ if (duplicates)
+ {
+ string namepart;
+ if (String.IsNullOrEmpty(descriptor.Name) || String.IsNullOrEmpty(namepart = Path.GetFileNameWithoutExtension(descriptor.Name)))
+ throw new ApplicationException("Duplicate UmbrellaClassname options created a file name collision.");
+
+ filename = namepart + descriptor.CSharpOptions.FileExtension;
+ }
+
+ string outputDirectory = descriptor.CSharpOptions.OutputDirectory;
+ if (fileOptions.ExpandNamespaceDirectories)
+ {
+ string package = fileOptions.Namespace;
+ if (!string.IsNullOrEmpty(package))
+ {
+ string[] bits = package.Split('.');
+ foreach (string bit in bits)
+ {
+ outputDirectory = Path.Combine(outputDirectory, bit);
+ }
+ }
+ }
+
+ // As the directory can be explicitly specified in options, we need to make sure it exists
+ Directory.CreateDirectory(outputDirectory);
+ return Path.Combine(outputDirectory, filename);
+ }
+
+ /// <summary>
+ /// Resolves any dependencies and converts FileDescriptorProtos into FileDescriptors.
+ /// The list returned is in the same order as the protos are listed in the descriptor set.
+ /// Note: this method is internal rather than private to allow testing.
+ /// </summary>
+ /// <exception cref="DependencyResolutionException">Not all dependencies could be resolved.</exception>
+ public static IList<FileDescriptor> ConvertDescriptors(CSharpFileOptions options,
+ IList<FileDescriptorProto> fileList)
+ {
+ FileDescriptor[] converted = new FileDescriptor[fileList.Count];
+
+ Dictionary<string, FileDescriptor> convertedMap = new Dictionary<string, FileDescriptor>();
+
+ int totalConverted = 0;
+
+ bool madeProgress = true;
+ while (madeProgress && totalConverted < converted.Length)
+ {
+ madeProgress = false;
+ for (int i = 0; i < converted.Length; i++)
+ {
+ if (converted[i] != null)
+ {
+ // Already done this one
+ continue;
+ }
+ FileDescriptorProto candidate = fileList[i];
+ FileDescriptor[] dependencies = new FileDescriptor[candidate.DependencyList.Count];
+
+
+ CSharpFileOptions.Builder builder = options.ToBuilder();
+ if (candidate.Options.HasExtension(CSharpOptions.CSharpFileOptions))
+ {
+ builder.MergeFrom(
+ candidate.Options.GetExtension(CSharpOptions.CSharpFileOptions));
+ }
+ CSharpFileOptions localOptions = builder.Build();
+
+ bool foundAllDependencies = true;
+ for (int j = 0; j < dependencies.Length; j++)
+ {
+ if (!convertedMap.TryGetValue(candidate.DependencyList[j], out dependencies[j]))
+ {
+ // We can auto-magically resolve these since we already have their description
+ // This way if the file is only referencing options it does not need to be built with the
+ // --include_imports definition.
+ if (localOptions.IgnoreGoogleProtobuf &&
+ (candidate.DependencyList[j] == "google/protobuf/csharp_options.proto"))
+ {
+ dependencies[j] = CSharpOptions.Descriptor;
+ continue;
+ }
+ if (localOptions.IgnoreGoogleProtobuf &&
+ (candidate.DependencyList[j] == "google/protobuf/descriptor.proto"))
+ {
+ dependencies[j] = DescriptorProtoFile.Descriptor;
+ continue;
+ }
+ foundAllDependencies = false;
+ break;
+ }
+ }
+ if (!foundAllDependencies)
+ {
+ continue;
+ }
+ madeProgress = true;
+ totalConverted++;
+ converted[i] = FileDescriptor.BuildFrom(candidate, dependencies);
+ convertedMap[candidate.Name] = converted[i];
+ }
+ }
+ if (!madeProgress)
+ {
+ StringBuilder remaining = new StringBuilder();
+ for (int i = 0; i < converted.Length; i++)
+ {
+ if (converted[i] == null)
+ {
+ if (remaining.Length != 0)
+ {
+ remaining.Append(", ");
+ }
+ FileDescriptorProto failure = fileList[i];
+ remaining.Append(failure.Name);
+ remaining.Append(":");
+ foreach (string dependency in failure.DependencyList)
+ {
+ if (!convertedMap.ContainsKey(dependency))
+ {
+ remaining.Append(" ");
+ remaining.Append(dependency);
+ }
+ }
+ remaining.Append(";");
+ }
+ }
+ throw new DependencyResolutionException("Unable to resolve all dependencies: " + remaining);
+ }
+ return Lists.AsReadOnly(converted);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/GeneratorOptions.cs b/csharp/src/ProtoGen/GeneratorOptions.cs
new file mode 100644
index 00000000..ec500d82
--- /dev/null
+++ b/csharp/src/ProtoGen/GeneratorOptions.cs
@@ -0,0 +1,330 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.RegularExpressions;
+using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// All the configuration required for the generator - where to generate
+ /// output files, the location of input files etc. While this isn't immutable
+ /// in practice, the contents shouldn't be changed after being passed to
+ /// the generator.
+ /// </summary>
+ public sealed class GeneratorOptions
+ {
+ private static Dictionary<string, string> LineBreaks =
+ new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
+ {
+ {"Windows", "\r\n"},
+ {"Unix", "\n"},
+ {"Default", Environment.NewLine}
+ };
+
+ public IList<string> InputFiles { get; set; }
+
+ public GeneratorOptions()
+ {
+ LineBreak = Environment.NewLine;
+ }
+
+ /// <summary>
+ /// Attempts to validate the options, but doesn't throw an exception if they're invalid.
+ /// Instead, when this method returns false, the output variable will contain a collection
+ /// of reasons for the validation failure.
+ /// </summary>
+ /// <param name="reasons">Variable to receive a list of reasons in case of validation failure.</param>
+ /// <returns>true if the options are valid; false otherwise</returns>
+ public bool TryValidate(out IList<string> reasons)
+ {
+ List<string> tmpReasons = new List<string>();
+
+ ParseArguments(tmpReasons);
+
+ // Output directory validation
+ if (string.IsNullOrEmpty(FileOptions.OutputDirectory))
+ {
+ tmpReasons.Add("No output directory specified");
+ }
+ else
+ {
+ if (!Directory.Exists(FileOptions.OutputDirectory))
+ {
+ tmpReasons.Add("Specified output directory (" + FileOptions.OutputDirectory + " doesn't exist.");
+ }
+ }
+
+ // Input file validation (just in terms of presence)
+ if (InputFiles == null || InputFiles.Count == 0)
+ {
+ tmpReasons.Add("No input files specified");
+ }
+ else
+ {
+ foreach (string input in InputFiles)
+ {
+ FileInfo fi = new FileInfo(input);
+ if (!fi.Exists)
+ {
+ tmpReasons.Add("Input file " + input + " doesn't exist.");
+ }
+ }
+ }
+
+ if (tmpReasons.Count != 0)
+ {
+ reasons = tmpReasons;
+ return false;
+ }
+
+ reasons = null;
+ return true;
+ }
+
+ /// <summary>
+ /// Validates that all the options have been set and are valid,
+ /// throwing an exception if they haven't.
+ /// </summary>
+ /// <exception cref="InvalidOptionsException">The options are invalid.</exception>
+ public void Validate()
+ {
+ IList<string> reasons;
+ if (!TryValidate(out reasons))
+ {
+ throw new InvalidOptionsException(reasons);
+ }
+ }
+
+ // Raw arguments, used to provide defaults for proto file options
+ public IList<string> Arguments { get; set; }
+
+ [Obsolete("Please use GeneratorOptions.FileOptions.OutputDirectory instead")]
+ public string OutputDirectory
+ {
+ get { return FileOptions.OutputDirectory; }
+ set
+ {
+ CSharpFileOptions.Builder bld = FileOptions.ToBuilder();
+ bld.OutputDirectory = value;
+ FileOptions = bld.Build();
+ }
+ }
+
+ private static readonly Regex ArgMatch = new Regex(@"^[-/](?<name>[\w_]+?)[:=](?<value>.*)$");
+ private CSharpFileOptions fileOptions;
+
+ public CSharpFileOptions FileOptions
+ {
+ get { return fileOptions ?? (fileOptions = CSharpFileOptions.DefaultInstance); }
+ set { fileOptions = value; }
+ }
+
+ public string LineBreak { get; set; }
+
+ private void ParseArguments(IList<string> tmpReasons)
+ {
+ bool doHelp = Arguments.Count == 0;
+
+ InputFiles = new List<string>();
+ CSharpFileOptions.Builder builder = FileOptions.ToBuilder();
+ Dictionary<string, FieldDescriptor> fields =
+ new Dictionary<string, FieldDescriptor>(StringComparer.OrdinalIgnoreCase);
+ foreach (FieldDescriptor fld in builder.DescriptorForType.Fields)
+ {
+ fields.Add(fld.Name, fld);
+ }
+
+ foreach (string argument in Arguments)
+ {
+ if (StringComparer.OrdinalIgnoreCase.Equals("-help", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("/help", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("-?", argument) ||
+ StringComparer.OrdinalIgnoreCase.Equals("/?", argument))
+ {
+ doHelp = true;
+ break;
+ }
+
+ Match m = ArgMatch.Match(argument);
+ if (m.Success)
+ {
+ FieldDescriptor fld;
+ string name = m.Groups["name"].Value;
+ string value = m.Groups["value"].Value;
+
+ if (fields.TryGetValue(name, out fld))
+ {
+ object obj;
+ if (TryCoerceType(value, fld, out obj, tmpReasons))
+ {
+ builder[fld] = obj;
+ }
+ }
+ else if (name == "line_break")
+ {
+ string tmp;
+ if (LineBreaks.TryGetValue(value, out tmp))
+ {
+ LineBreak = tmp;
+ }
+ else
+ {
+ tmpReasons.Add("Invalid value for 'line_break': " + value + ".");
+ }
+ }
+ else if (!File.Exists(argument))
+ {
+ doHelp = true;
+ tmpReasons.Add("Unknown argument '" + name + "'.");
+ }
+ else
+ {
+ InputFiles.Add(argument);
+ }
+ }
+ else
+ {
+ InputFiles.Add(argument);
+ }
+ }
+
+ if (doHelp || InputFiles.Count == 0)
+ {
+ tmpReasons.Add("Arguments:");
+ foreach (KeyValuePair<string, FieldDescriptor> field in fields)
+ {
+ tmpReasons.Add(String.Format("-{0}=[{1}]", field.Key, field.Value.FieldType));
+ }
+ tmpReasons.Add("-line_break=[" + string.Join("|", new List<string>(LineBreaks.Keys).ToArray()) + "]");
+ tmpReasons.Add("followed by one or more file paths.");
+ }
+ else
+ {
+ FileOptions = builder.Build();
+ }
+ }
+
+ private static bool TryCoerceType(string text, FieldDescriptor field, out object value, IList<string> tmpReasons)
+ {
+ value = null;
+
+ switch (field.FieldType)
+ {
+ case FieldType.Int32:
+ case FieldType.SInt32:
+ case FieldType.SFixed32:
+ value = Int32.Parse(text);
+ break;
+
+ case FieldType.Int64:
+ case FieldType.SInt64:
+ case FieldType.SFixed64:
+ value = Int64.Parse(text);
+ break;
+
+ case FieldType.UInt32:
+ case FieldType.Fixed32:
+ value = UInt32.Parse(text);
+ break;
+
+ case FieldType.UInt64:
+ case FieldType.Fixed64:
+ value = UInt64.Parse(text);
+ break;
+
+ case FieldType.Float:
+ value = float.Parse(text);
+ break;
+
+ case FieldType.Double:
+ value = Double.Parse(text);
+ break;
+
+ case FieldType.Bool:
+ value = Boolean.Parse(text);
+ break;
+
+ case FieldType.String:
+ value = text;
+ break;
+
+ case FieldType.Enum:
+ {
+ EnumDescriptor enumType = field.EnumType;
+
+ int number;
+ if (int.TryParse(text, out number))
+ {
+ value = enumType.FindValueByNumber(number);
+ if (value == null)
+ {
+ tmpReasons.Add(
+ "Enum type \"" + enumType.FullName +
+ "\" has no value with number " + number + ".");
+ return false;
+ }
+ }
+ else
+ {
+ value = enumType.FindValueByName(text);
+ if (value == null)
+ {
+ tmpReasons.Add(
+ "Enum type \"" + enumType.FullName +
+ "\" has no value named \"" + text + "\".");
+ return false;
+ }
+ }
+
+ break;
+ }
+
+ case FieldType.Bytes:
+ case FieldType.Message:
+ case FieldType.Group:
+ tmpReasons.Add("Unhandled field type " + field.FieldType.ToString() + ".");
+ return false;
+ }
+
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/Helpers.cs b/csharp/src/ProtoGen/Helpers.cs
new file mode 100644
index 00000000..3c001150
--- /dev/null
+++ b/csharp/src/ProtoGen/Helpers.cs
@@ -0,0 +1,45 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// Helpers to resolve class names etc.
+ /// </summary>
+ internal static class Helpers
+ {
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/IFieldSourceGenerator.cs b/csharp/src/ProtoGen/IFieldSourceGenerator.cs
new file mode 100644
index 00000000..f53ae5e4
--- /dev/null
+++ b/csharp/src/ProtoGen/IFieldSourceGenerator.cs
@@ -0,0 +1,53 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal interface IFieldSourceGenerator
+ {
+ void GenerateMembers(TextGenerator writer);
+ void GenerateBuilderMembers(TextGenerator writer);
+ void GenerateMergingCode(TextGenerator writer);
+ void GenerateBuildingCode(TextGenerator writer);
+ void GenerateParsingCode(TextGenerator writer);
+ void GenerateSerializationCode(TextGenerator writer);
+ void GenerateSerializedSizeCode(TextGenerator writer);
+
+ void WriteHash(TextGenerator writer);
+ void WriteEquals(TextGenerator writer);
+ void WriteToString(TextGenerator writer);
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/ISourceGenerator.cs b/csharp/src/ProtoGen/ISourceGenerator.cs
new file mode 100644
index 00000000..452d854a
--- /dev/null
+++ b/csharp/src/ProtoGen/ISourceGenerator.cs
@@ -0,0 +1,43 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal interface ISourceGenerator
+ {
+ void Generate(TextGenerator writer);
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/InvalidOptionsException.cs b/csharp/src/ProtoGen/InvalidOptionsException.cs
new file mode 100644
index 00000000..fb698495
--- /dev/null
+++ b/csharp/src/ProtoGen/InvalidOptionsException.cs
@@ -0,0 +1,77 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Google.ProtocolBuffers.Collections;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// Exception thrown to indicate that the options passed were invalid.
+ /// </summary>
+ public sealed class InvalidOptionsException : Exception
+ {
+ private readonly IList<string> reasons;
+
+ /// <summary>
+ /// An immutable list of reasons why the options were invalid.
+ /// </summary>
+ public IList<string> Reasons
+ {
+ get { return reasons; }
+ }
+
+ public InvalidOptionsException(IList<string> reasons)
+ : base(BuildMessage(reasons))
+ {
+ this.reasons = Lists.AsReadOnly(reasons);
+ }
+
+ private static string BuildMessage(IEnumerable<string> reasons)
+ {
+ StringBuilder builder = new StringBuilder("Invalid options:");
+ builder.AppendLine();
+ foreach (string reason in reasons)
+ {
+ builder.Append(" ");
+ builder.AppendLine(reason);
+ }
+ return builder.ToString();
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/MessageFieldGenerator.cs b/csharp/src/ProtoGen/MessageFieldGenerator.cs
new file mode 100644
index 00000000..25b58a60
--- /dev/null
+++ b/csharp/src/ProtoGen/MessageFieldGenerator.cs
@@ -0,0 +1,174 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class MessageFieldGenerator : FieldGeneratorBase, IFieldSourceGenerator
+ {
+ internal MessageFieldGenerator(FieldDescriptor descriptor, int fieldOrdinal)
+ : base(descriptor, fieldOrdinal)
+ {
+ }
+
+ public void GenerateMembers(TextGenerator writer)
+ {
+ writer.WriteLine("private bool has{0};", PropertyName);
+ writer.WriteLine("private {0} {1}_;", TypeName, Name);
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public bool Has{0} {{", PropertyName);
+ writer.WriteLine(" get {{ return has{0}; }}", PropertyName);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return {0}_ ?? {1}; }}", Name, DefaultValue);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuilderMembers(TextGenerator writer)
+ {
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public bool Has{0} {{", PropertyName);
+ writer.WriteLine(" get {{ return result.has{0}; }}", PropertyName);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return result.{0}; }}", PropertyName);
+ writer.WriteLine(" set {{ Set{0}(value); }}", PropertyName);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
+ AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.has{0} = true;", PropertyName);
+ writer.WriteLine(" result.{0}_ = value;", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Set{0}({1}.Builder builderForValue) {{", PropertyName, TypeName);
+ AddNullCheck(writer, "builderForValue");
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.has{0} = true;", PropertyName);
+ writer.WriteLine(" result.{0}_ = builderForValue.Build();", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Merge{0}({1} value) {{", PropertyName, TypeName);
+ AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" if (result.has{0} &&", PropertyName);
+ writer.WriteLine(" result.{0}_ != {1}) {{", Name, DefaultValue);
+ writer.WriteLine(" result.{0}_ = {1}.CreateBuilder(result.{0}_).MergeFrom(value).BuildPartial();", Name,
+ TypeName);
+ writer.WriteLine(" } else {");
+ writer.WriteLine(" result.{0}_ = value;", Name);
+ writer.WriteLine(" }");
+ writer.WriteLine(" result.has{0} = true;", PropertyName);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.has{0} = false;", PropertyName);
+ writer.WriteLine(" result.{0}_ = null;", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ }
+
+ public void GenerateMergingCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (other.Has{0}) {{", PropertyName);
+ writer.WriteLine(" Merge{0}(other.{0});", PropertyName);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuildingCode(TextGenerator writer)
+ {
+ // Nothing to do for singular fields
+ }
+
+ public void GenerateParsingCode(TextGenerator writer)
+ {
+ writer.WriteLine("{0}.Builder subBuilder = {0}.CreateBuilder();", TypeName);
+ writer.WriteLine("if (result.has{0}) {{", PropertyName);
+ writer.WriteLine(" subBuilder.MergeFrom({0});", PropertyName);
+ writer.WriteLine("}");
+ if (Descriptor.FieldType == FieldType.Group)
+ {
+ writer.WriteLine("input.ReadGroup({0}, subBuilder, extensionRegistry);", Number);
+ }
+ else
+ {
+ writer.WriteLine("input.ReadMessage(subBuilder, extensionRegistry);");
+ }
+ writer.WriteLine("{0} = subBuilder.BuildPartial();", PropertyName);
+ }
+
+ public void GenerateSerializationCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) {{", PropertyName);
+ writer.WriteLine(" output.Write{0}({1}, field_names[{3}], {2});", MessageOrGroup, Number, PropertyName,
+ FieldOrdinal);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateSerializedSizeCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) {{", PropertyName);
+ writer.WriteLine(" size += pb::CodedOutputStream.Compute{0}Size({1}, {2});",
+ MessageOrGroup, Number, PropertyName);
+ writer.WriteLine("}");
+ }
+
+ public override void WriteHash(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) hash ^= {1}_.GetHashCode();", PropertyName, Name);
+ }
+
+ public override void WriteEquals(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0} != other.has{0} || (has{0} && !{1}_.Equals(other.{1}_))) return false;",
+ PropertyName, Name);
+ }
+
+ public override void WriteToString(TextGenerator writer)
+ {
+ writer.WriteLine("PrintField(\"{2}\", has{0}, {1}_, writer);", PropertyName, Name,
+ Descriptor.FieldType == FieldType.Group ? Descriptor.MessageType.Name : Descriptor.Name);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/MessageGenerator.cs b/csharp/src/ProtoGen/MessageGenerator.cs
new file mode 100644
index 00000000..e7ed1e86
--- /dev/null
+++ b/csharp/src/ProtoGen/MessageGenerator.cs
@@ -0,0 +1,893 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class MessageGenerator : SourceGeneratorBase<MessageDescriptor>, ISourceGenerator
+ {
+ private string[] _fieldNames;
+
+ internal MessageGenerator(MessageDescriptor descriptor) : base(descriptor)
+ {
+ }
+
+ private string ClassName
+ {
+ get { return Descriptor.Name; }
+ }
+
+ private string FullClassName
+ {
+ get { return GetClassName(Descriptor); }
+ }
+
+ /// <summary>
+ /// Get an identifier that uniquely identifies this type within the file.
+ /// This is used to declare static variables related to this type at the
+ /// outermost file scope.
+ /// </summary>
+ private static string GetUniqueFileScopeIdentifier(IDescriptor descriptor)
+ {
+ return "static_" + descriptor.FullName.Replace(".", "_");
+ }
+
+ internal void GenerateStaticVariables(TextGenerator writer)
+ {
+ // Because descriptor.proto (Google.ProtocolBuffers.DescriptorProtos) is
+ // used in the construction of descriptors, we have a tricky bootstrapping
+ // problem. To help control static initialization order, we make sure all
+ // descriptors and other static data that depends on them are members of
+ // the proto-descriptor class. This way, they will be initialized in
+ // a deterministic order.
+
+ string identifier = GetUniqueFileScopeIdentifier(Descriptor);
+
+ if (!UseLiteRuntime)
+ {
+ // The descriptor for this type.
+ string access = Descriptor.File.CSharpOptions.NestClasses ? "private" : "internal";
+ writer.WriteLine("{0} static pbd::MessageDescriptor internal__{1}__Descriptor;", access, identifier);
+ writer.WriteLine(
+ "{0} static pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder> internal__{2}__FieldAccessorTable;",
+ access, FullClassName, identifier);
+ }
+ // Generate static members for all nested types.
+ foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes)
+ {
+ new MessageGenerator(nestedMessage).GenerateStaticVariables(writer);
+ }
+ }
+
+ internal void GenerateStaticVariableInitializers(TextGenerator writer)
+ {
+ string identifier = GetUniqueFileScopeIdentifier(Descriptor);
+
+ if (!UseLiteRuntime)
+ {
+ writer.Write("internal__{0}__Descriptor = ", identifier);
+ if (Descriptor.ContainingType == null)
+ {
+ writer.WriteLine("Descriptor.MessageTypes[{0}];", Descriptor.Index);
+ }
+ else
+ {
+ writer.WriteLine("internal__{0}__Descriptor.NestedTypes[{1}];",
+ GetUniqueFileScopeIdentifier(Descriptor.ContainingType), Descriptor.Index);
+ }
+
+ writer.WriteLine("internal__{0}__FieldAccessorTable = ", identifier);
+ writer.WriteLine(
+ " new pb::FieldAccess.FieldAccessorTable<{1}, {1}.Builder>(internal__{0}__Descriptor,",
+ identifier, FullClassName);
+ writer.Print(" new string[] { ");
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ writer.Write("\"{0}\", ", field.CSharpOptions.PropertyName);
+ }
+ writer.WriteLine("});");
+ }
+
+ // Generate static member initializers for all nested types.
+ foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes)
+ {
+ new MessageGenerator(nestedMessage).GenerateStaticVariableInitializers(writer);
+ }
+
+ foreach (FieldDescriptor extension in Descriptor.Extensions)
+ {
+ new ExtensionGenerator(extension).GenerateStaticVariableInitializers(writer);
+ }
+ }
+
+ public string[] FieldNames
+ {
+ get
+ {
+ if (_fieldNames == null)
+ {
+ List<string> names = new List<string>();
+ foreach (FieldDescriptor fieldDescriptor in Descriptor.Fields)
+ {
+ names.Add(fieldDescriptor.Name);
+ }
+ //if you change this, the search must also change in GenerateBuilderParsingMethods
+ names.Sort(StringComparer.Ordinal);
+ _fieldNames = names.ToArray();
+ }
+ return _fieldNames;
+ }
+ }
+
+ internal int FieldOrdinal(FieldDescriptor field)
+ {
+ return Array.BinarySearch(FieldNames, field.Name, StringComparer.Ordinal);
+ }
+
+ private IFieldSourceGenerator CreateFieldGenerator(FieldDescriptor fieldDescriptor)
+ {
+ return SourceGenerators.CreateFieldGenerator(fieldDescriptor, FieldOrdinal(fieldDescriptor));
+ }
+
+ public void Generate(TextGenerator writer)
+ {
+ if (Descriptor.File.CSharpOptions.AddSerializable)
+ {
+ writer.WriteLine("[global::System.SerializableAttribute()]");
+ }
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("{0} sealed partial class {1} : pb::{2}Message{3}<{1}, {1}.Builder> {{",
+ ClassAccessLevel, ClassName,
+ Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated",
+ RuntimeSuffix);
+ writer.Indent();
+ if (Descriptor.File.CSharpOptions.GeneratePrivateCtor)
+ {
+ writer.WriteLine("private {0}() {{ }}", ClassName);
+ }
+ // Must call MakeReadOnly() to make sure all lists are made read-only
+ writer.WriteLine("private static readonly {0} defaultInstance = new {0}().MakeReadOnly();", ClassName);
+
+ if (OptimizeSpeed)
+ {
+ writer.WriteLine("private static readonly string[] _{0}FieldNames = new string[] {{ {2}{1}{2} }};",
+ NameHelpers.UnderscoresToCamelCase(ClassName), String.Join("\", \"", FieldNames),
+ FieldNames.Length > 0 ? "\"" : "");
+ List<string> tags = new List<string>();
+ foreach (string name in FieldNames)
+ {
+ tags.Add(WireFormat.MakeTag(Descriptor.FindFieldByName(name)).ToString());
+ }
+
+ writer.WriteLine("private static readonly uint[] _{0}FieldTags = new uint[] {{ {1} }};",
+ NameHelpers.UnderscoresToCamelCase(ClassName), String.Join(", ", tags.ToArray()));
+ }
+ writer.WriteLine("public static {0} DefaultInstance {{", ClassName);
+ writer.WriteLine(" get { return defaultInstance; }");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("public override {0} DefaultInstanceForType {{", ClassName);
+ writer.WriteLine(" get { return DefaultInstance; }");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("protected override {0} ThisMessage {{", ClassName);
+ writer.WriteLine(" get { return this; }");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine("public static pbd::MessageDescriptor Descriptor {");
+ writer.WriteLine(" get {{ return {0}.internal__{1}__Descriptor; }}",
+ DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
+ GetUniqueFileScopeIdentifier(Descriptor));
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine(
+ "protected override pb::FieldAccess.FieldAccessorTable<{0}, {0}.Builder> InternalFieldAccessors {{",
+ ClassName);
+ writer.WriteLine(" get {{ return {0}.internal__{1}__FieldAccessorTable; }}",
+ DescriptorUtil.GetFullUmbrellaClassName(Descriptor),
+ GetUniqueFileScopeIdentifier(Descriptor));
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+
+ // Extensions don't need to go in an extra nested type
+ WriteChildren(writer, null, Descriptor.Extensions);
+
+ if (Descriptor.EnumTypes.Count + Descriptor.NestedTypes.Count > 0)
+ {
+ writer.WriteLine("#region Nested types");
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("public static partial class Types {");
+ writer.Indent();
+ WriteChildren(writer, null, Descriptor.EnumTypes);
+ WriteChildren(writer, null, Descriptor.NestedTypes);
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine("#endregion");
+ writer.WriteLine();
+ }
+
+ foreach (FieldDescriptor fieldDescriptor in Descriptor.Fields)
+ {
+ if (Descriptor.File.CSharpOptions.ClsCompliance && GetFieldConstantName(fieldDescriptor).StartsWith("_"))
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+
+ // Rats: we lose the debug comment here :(
+ writer.WriteLine("public const int {0} = {1};", GetFieldConstantName(fieldDescriptor),
+ fieldDescriptor.FieldNumber);
+ CreateFieldGenerator(fieldDescriptor).GenerateMembers(writer);
+ writer.WriteLine();
+ }
+
+ if (OptimizeSpeed)
+ {
+ GenerateIsInitialized(writer);
+ GenerateMessageSerializationMethods(writer);
+ }
+ if (UseLiteRuntime)
+ {
+ GenerateLiteRuntimeMethods(writer);
+ }
+
+ GenerateParseFromMethods(writer);
+ GenerateBuilder(writer);
+
+ // Force the static initialization code for the file to run, since it may
+ // initialize static variables declared in this class.
+ writer.WriteLine("static {0}() {{", ClassName);
+ // We call object.ReferenceEquals() just to make it a valid statement on its own.
+ // Another option would be GetType(), but that causes problems in DescriptorProtoFile,
+ // where the bootstrapping is somewhat recursive - type initializers call
+ // each other, effectively. We temporarily see Descriptor as null.
+ writer.WriteLine(" object.ReferenceEquals({0}.Descriptor, null);",
+ DescriptorUtil.GetFullUmbrellaClassName(Descriptor));
+ writer.WriteLine("}");
+
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+
+ private void GenerateLiteRuntimeMethods(TextGenerator writer)
+ {
+ bool callbase = Descriptor.Proto.ExtensionRangeCount > 0;
+ writer.WriteLine("#region Lite runtime methods");
+ writer.WriteLine("public override int GetHashCode() {");
+ writer.Indent();
+ writer.WriteLine("int hash = GetType().GetHashCode();");
+ foreach (FieldDescriptor fieldDescriptor in Descriptor.Fields)
+ {
+ CreateFieldGenerator(fieldDescriptor).WriteHash(writer);
+ }
+ if (callbase)
+ {
+ writer.WriteLine("hash ^= base.GetHashCode();");
+ }
+ writer.WriteLine("return hash;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine("public override bool Equals(object obj) {");
+ writer.Indent();
+ writer.WriteLine("{0} other = obj as {0};", ClassName);
+ writer.WriteLine("if (other == null) return false;");
+ foreach (FieldDescriptor fieldDescriptor in Descriptor.Fields)
+ {
+ CreateFieldGenerator(fieldDescriptor).WriteEquals(writer);
+ }
+ if (callbase)
+ {
+ writer.WriteLine("if (!base.Equals(other)) return false;");
+ }
+ writer.WriteLine("return true;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine("public override void PrintTo(global::System.IO.TextWriter writer) {");
+ writer.Indent();
+ List<FieldDescriptor> sorted = new List<FieldDescriptor>(Descriptor.Fields);
+ sorted.Sort(
+ new Comparison<FieldDescriptor>(
+ delegate(FieldDescriptor a, FieldDescriptor b) { return a.FieldNumber.CompareTo(b.FieldNumber); }));
+ foreach (FieldDescriptor fieldDescriptor in sorted)
+ {
+ CreateFieldGenerator(fieldDescriptor).WriteToString(writer);
+ }
+ if (callbase)
+ {
+ writer.WriteLine("base.PrintTo(writer);");
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine("#endregion");
+ writer.WriteLine();
+ }
+
+ private void GenerateMessageSerializationMethods(TextGenerator writer)
+ {
+ List<FieldDescriptor> sortedFields = new List<FieldDescriptor>(Descriptor.Fields);
+ sortedFields.Sort((f1, f2) => f1.FieldNumber.CompareTo(f2.FieldNumber));
+
+ List<DescriptorProto.Types.ExtensionRange> sortedExtensions =
+ new List<DescriptorProto.Types.ExtensionRange>(Descriptor.Proto.ExtensionRangeList);
+ sortedExtensions.Sort((r1, r2) => (r1.Start.CompareTo(r2.Start)));
+
+ writer.WriteLine("public override void WriteTo(pb::ICodedOutputStream output) {");
+ writer.Indent();
+ // Make sure we've computed the serialized length, so that packed fields are generated correctly.
+ writer.WriteLine("CalcSerializedSize();");
+ writer.WriteLine("string[] field_names = _{0}FieldNames;", NameHelpers.UnderscoresToCamelCase(ClassName));
+ if (Descriptor.Proto.ExtensionRangeList.Count > 0)
+ {
+ writer.WriteLine(
+ "pb::ExtendableMessage{1}<{0}, {0}.Builder>.ExtensionWriter extensionWriter = CreateExtensionWriter(this);",
+ ClassName, RuntimeSuffix);
+ }
+
+ // Merge the fields and the extension ranges, both sorted by field number.
+ for (int i = 0, j = 0; i < Descriptor.Fields.Count || j < sortedExtensions.Count;)
+ {
+ if (i == Descriptor.Fields.Count)
+ {
+ GenerateSerializeOneExtensionRange(writer, sortedExtensions[j++]);
+ }
+ else if (j == sortedExtensions.Count)
+ {
+ GenerateSerializeOneField(writer, sortedFields[i++]);
+ }
+ else if (sortedFields[i].FieldNumber < sortedExtensions[j].Start)
+ {
+ GenerateSerializeOneField(writer, sortedFields[i++]);
+ }
+ else
+ {
+ GenerateSerializeOneExtensionRange(writer, sortedExtensions[j++]);
+ }
+ }
+
+ if (!UseLiteRuntime)
+ {
+ if (Descriptor.Proto.Options.MessageSetWireFormat)
+ {
+ writer.WriteLine("UnknownFields.WriteAsMessageSetTo(output);");
+ }
+ else
+ {
+ writer.WriteLine("UnknownFields.WriteTo(output);");
+ }
+ }
+
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("private int memoizedSerializedSize = -1;");
+ writer.WriteLine("public override int SerializedSize {");
+ writer.Indent();
+ writer.WriteLine("get {");
+ writer.Indent();
+ writer.WriteLine("int size = memoizedSerializedSize;");
+ writer.WriteLine("if (size != -1) return size;");
+ writer.WriteLine("return CalcSerializedSize();");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine("private int CalcSerializedSize() {");
+ writer.Indent();
+ writer.WriteLine("int size = memoizedSerializedSize;");
+ writer.WriteLine("if (size != -1) return size;");
+ writer.WriteLine();
+ writer.WriteLine("size = 0;");
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ CreateFieldGenerator(field).GenerateSerializedSizeCode(writer);
+ }
+ if (Descriptor.Proto.ExtensionRangeCount > 0)
+ {
+ writer.WriteLine("size += ExtensionsSerializedSize;");
+ }
+
+ if (!UseLiteRuntime)
+ {
+ if (Descriptor.Options.MessageSetWireFormat)
+ {
+ writer.WriteLine("size += UnknownFields.SerializedSizeAsMessageSet;");
+ }
+ else
+ {
+ writer.WriteLine("size += UnknownFields.SerializedSize;");
+ }
+ }
+ writer.WriteLine("memoizedSerializedSize = size;");
+ writer.WriteLine("return size;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+
+ private void GenerateSerializeOneField(TextGenerator writer, FieldDescriptor fieldDescriptor)
+ {
+ CreateFieldGenerator(fieldDescriptor).GenerateSerializationCode(writer);
+ }
+
+ private static void GenerateSerializeOneExtensionRange(TextGenerator writer,
+ DescriptorProto.Types.ExtensionRange extensionRange)
+ {
+ writer.WriteLine("extensionWriter.WriteUntil({0}, output);", extensionRange.End);
+ }
+
+ private void GenerateParseFromMethods(TextGenerator writer)
+ {
+ // Note: These are separate from GenerateMessageSerializationMethods()
+ // because they need to be generated even for messages that are optimized
+ // for code size.
+
+ writer.WriteLine("public static {0} ParseFrom(pb::ByteString data) {{", ClassName);
+ writer.WriteLine(" return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine(
+ "public static {0} ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {{",
+ ClassName);
+ writer.WriteLine(" return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine("public static {0} ParseFrom(byte[] data) {{", ClassName);
+ writer.WriteLine(" return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine("public static {0} ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {{",
+ ClassName);
+ writer.WriteLine(" return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine("public static {0} ParseFrom(global::System.IO.Stream input) {{", ClassName);
+ writer.WriteLine(" return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine(
+ "public static {0} ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {{",
+ ClassName);
+ writer.WriteLine(" return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine("public static {0} ParseDelimitedFrom(global::System.IO.Stream input) {{", ClassName);
+ writer.WriteLine(" return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine(
+ "public static {0} ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {{",
+ ClassName);
+ writer.WriteLine(" return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine("public static {0} ParseFrom(pb::ICodedInputStream input) {{", ClassName);
+ writer.WriteLine(" return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();");
+ writer.WriteLine("}");
+ writer.WriteLine(
+ "public static {0} ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {{",
+ ClassName);
+ writer.WriteLine(" return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();");
+ writer.WriteLine("}");
+ }
+
+ /// <summary>
+ /// Returns whether or not the specified message type has any required fields.
+ /// If it doesn't, calls to check for initialization can be optimised.
+ /// TODO(jonskeet): Move this into MessageDescriptor?
+ /// </summary>
+ private static bool HasRequiredFields(MessageDescriptor descriptor,
+ Dictionary<MessageDescriptor, object> alreadySeen)
+ {
+ if (alreadySeen.ContainsKey(descriptor))
+ {
+ // The type is already in cache. This means that either:
+ // a. The type has no required fields.
+ // b. We are in the midst of checking if the type has required fields,
+ // somewhere up the stack. In this case, we know that if the type
+ // has any required fields, they'll be found when we return to it,
+ // and the whole call to HasRequiredFields() will return true.
+ // Therefore, we don't have to check if this type has required fields
+ // here.
+ return false;
+ }
+ alreadySeen[descriptor] = descriptor; // Value is irrelevant
+
+ // If the type has extensions, an extension with message type could contain
+ // required fields, so we have to be conservative and assume such an
+ // extension exists.
+ if (descriptor.Extensions.Count > 0)
+ {
+ return true;
+ }
+
+ foreach (FieldDescriptor field in descriptor.Fields)
+ {
+ if (field.IsRequired)
+ {
+ return true;
+ }
+ // Message or group
+ if (field.MappedType == MappedType.Message)
+ {
+ if (HasRequiredFields(field.MessageType, alreadySeen))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void GenerateBuilder(TextGenerator writer)
+ {
+ writer.WriteLine("private {0} MakeReadOnly() {{", ClassName);
+ writer.Indent();
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ CreateFieldGenerator(field).GenerateBuildingCode(writer);
+ }
+ writer.WriteLine("return this;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine("public static Builder CreateBuilder() { return new Builder(); }");
+ writer.WriteLine("public override Builder ToBuilder() { return CreateBuilder(this); }");
+ writer.WriteLine("public override Builder CreateBuilderForType() { return new Builder(); }");
+ writer.WriteLine("public static Builder CreateBuilder({0} prototype) {{", ClassName);
+ writer.WriteLine(" return new Builder(prototype);");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ if (Descriptor.File.CSharpOptions.AddSerializable)
+ {
+ writer.WriteLine("[global::System.SerializableAttribute()]");
+ }
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("{0} sealed partial class Builder : pb::{2}Builder{3}<{1}, Builder> {{",
+ ClassAccessLevel, ClassName,
+ Descriptor.Proto.ExtensionRangeCount > 0 ? "Extendable" : "Generated", RuntimeSuffix);
+ writer.Indent();
+ writer.WriteLine("protected override Builder ThisBuilder {");
+ writer.WriteLine(" get { return this; }");
+ writer.WriteLine("}");
+ GenerateCommonBuilderMethods(writer);
+ if (OptimizeSpeed)
+ {
+ GenerateBuilderParsingMethods(writer);
+ }
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ writer.WriteLine();
+ // No field comment :(
+ CreateFieldGenerator(field).GenerateBuilderMembers(writer);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+
+ private void GenerateCommonBuilderMethods(TextGenerator writer)
+ {
+ //default constructor
+ writer.WriteLine("public Builder() {");
+ //Durring static initialization of message, DefaultInstance is expected to return null.
+ writer.WriteLine(" result = DefaultInstance;");
+ writer.WriteLine(" resultIsReadOnly = true;");
+ writer.WriteLine("}");
+ //clone constructor
+ writer.WriteLine("internal Builder({0} cloneFrom) {{", ClassName);
+ writer.WriteLine(" result = cloneFrom;");
+ writer.WriteLine(" resultIsReadOnly = true;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("private bool resultIsReadOnly;");
+ writer.WriteLine("private {0} result;", ClassName);
+ writer.WriteLine();
+ writer.WriteLine("private {0} PrepareBuilder() {{", ClassName);
+ writer.WriteLine(" if (resultIsReadOnly) {");
+ writer.WriteLine(" {0} original = result;", ClassName);
+ writer.WriteLine(" result = new {0}();", ClassName);
+ writer.WriteLine(" resultIsReadOnly = false;");
+ writer.WriteLine(" MergeFrom(original);");
+ writer.WriteLine(" }");
+ writer.WriteLine(" return result;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("public override bool IsInitialized {");
+ writer.WriteLine(" get { return result.IsInitialized; }");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("protected override {0} MessageBeingBuilt {{", ClassName);
+ writer.WriteLine(" get { return PrepareBuilder(); }");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ //Not actually expecting that DefaultInstance would ever be null here; however, we will ensure it does not break
+ writer.WriteLine("public override Builder Clear() {");
+ writer.WriteLine(" result = DefaultInstance;", ClassName);
+ writer.WriteLine(" resultIsReadOnly = true;");
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("public override Builder Clone() {");
+ writer.WriteLine(" if (resultIsReadOnly) {");
+ writer.WriteLine(" return new Builder(result);");
+ writer.WriteLine(" } else {");
+ writer.WriteLine(" return new Builder().MergeFrom(result);");
+ writer.WriteLine(" }");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine("public override pbd::MessageDescriptor DescriptorForType {");
+ writer.WriteLine(" get {{ return {0}.Descriptor; }}", FullClassName);
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+ writer.WriteLine("public override {0} DefaultInstanceForType {{", ClassName);
+ writer.WriteLine(" get {{ return {0}.DefaultInstance; }}", FullClassName);
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine("public override {0} BuildPartial() {{", ClassName);
+ writer.Indent();
+ writer.WriteLine("if (resultIsReadOnly) {");
+ writer.WriteLine(" return result;");
+ writer.WriteLine("}");
+ writer.WriteLine("resultIsReadOnly = true;");
+ writer.WriteLine("return result.MakeReadOnly();");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ if (OptimizeSpeed)
+ {
+ writer.WriteLine("public override Builder MergeFrom(pb::IMessage{0} other) {{", RuntimeSuffix);
+ writer.WriteLine(" if (other is {0}) {{", ClassName);
+ writer.WriteLine(" return MergeFrom(({0}) other);", ClassName);
+ writer.WriteLine(" } else {");
+ writer.WriteLine(" base.MergeFrom(other);");
+ writer.WriteLine(" return this;");
+ writer.WriteLine(" }");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("public override Builder MergeFrom({0} other) {{", ClassName);
+ // Optimization: If other is the default instance, we know none of its
+ // fields are set so we can skip the merge.
+ writer.Indent();
+ writer.WriteLine("if (other == {0}.DefaultInstance) return this;", FullClassName);
+ writer.WriteLine("PrepareBuilder();");
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ CreateFieldGenerator(field).GenerateMergingCode(writer);
+ }
+ // if message type has extensions
+ if (Descriptor.Proto.ExtensionRangeCount > 0)
+ {
+ writer.WriteLine(" this.MergeExtensionFields(other);");
+ }
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine("this.MergeUnknownFields(other.UnknownFields);");
+ }
+ writer.WriteLine("return this;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+ }
+
+ private void GenerateBuilderParsingMethods(TextGenerator writer)
+ {
+ List<FieldDescriptor> sortedFields = new List<FieldDescriptor>(Descriptor.Fields);
+ sortedFields.Sort((f1, f2) => f1.FieldNumber.CompareTo(f2.FieldNumber));
+
+ writer.WriteLine("public override Builder MergeFrom(pb::ICodedInputStream input) {");
+ writer.WriteLine(" return MergeFrom(input, pb::ExtensionRegistry.Empty);");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine(
+ "public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {");
+ writer.Indent();
+ writer.WriteLine("PrepareBuilder();");
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;");
+ }
+ writer.WriteLine("uint tag;");
+ writer.WriteLine("string field_name;");
+ writer.WriteLine("while (input.ReadTag(out tag, out field_name)) {");
+ writer.Indent();
+ writer.WriteLine("if(tag == 0 && field_name != null) {");
+ writer.Indent();
+ //if you change from StringComparer.Ordinal, the array sort in FieldNames { get; } must also change
+ writer.WriteLine(
+ "int field_ordinal = global::System.Array.BinarySearch(_{0}FieldNames, field_name, global::System.StringComparer.Ordinal);",
+ NameHelpers.UnderscoresToCamelCase(ClassName));
+ writer.WriteLine("if(field_ordinal >= 0)");
+ writer.WriteLine(" tag = _{0}FieldTags[field_ordinal];", NameHelpers.UnderscoresToCamelCase(ClassName));
+ writer.WriteLine("else {");
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now
+ writer.WriteLine(" unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);");
+ writer.WriteLine(" }");
+ }
+ writer.WriteLine(" ParseUnknownField(input, {0}extensionRegistry, tag, field_name);",
+ UseLiteRuntime ? "" : "unknownFields, ");
+ writer.WriteLine(" continue;");
+ writer.WriteLine("}");
+ writer.Outdent();
+ writer.WriteLine("}");
+
+ writer.WriteLine("switch (tag) {");
+ writer.Indent();
+ writer.WriteLine("case 0: {"); // 0 signals EOF / limit reached
+ writer.WriteLine(" throw pb::InvalidProtocolBufferException.InvalidTag();");
+ writer.WriteLine("}");
+ writer.WriteLine("default: {");
+ writer.WriteLine(" if (pb::WireFormat.IsEndGroupTag(tag)) {");
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine(" if (unknownFields != null) {");
+ writer.WriteLine(" this.UnknownFields = unknownFields.Build();");
+ writer.WriteLine(" }");
+ }
+ writer.WriteLine(" return this;"); // it's an endgroup tag
+ writer.WriteLine(" }");
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now
+ writer.WriteLine(" unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);");
+ writer.WriteLine(" }");
+ }
+ writer.WriteLine(" ParseUnknownField(input, {0}extensionRegistry, tag, field_name);",
+ UseLiteRuntime ? "" : "unknownFields, ");
+ writer.WriteLine(" break;");
+ writer.WriteLine("}");
+ foreach (FieldDescriptor field in sortedFields)
+ {
+ WireFormat.WireType wt = WireFormat.GetWireType(field.FieldType);
+ uint tag = WireFormat.MakeTag(field.FieldNumber, wt);
+
+ if (field.IsRepeated &&
+ (wt == WireFormat.WireType.Varint || wt == WireFormat.WireType.Fixed32 ||
+ wt == WireFormat.WireType.Fixed64))
+ {
+ writer.WriteLine("case {0}:",
+ WireFormat.MakeTag(field.FieldNumber, WireFormat.WireType.LengthDelimited));
+ }
+
+ writer.WriteLine("case {0}: {{", tag);
+ writer.Indent();
+ CreateFieldGenerator(field).GenerateParsingCode(writer);
+ writer.WriteLine("break;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine("if (unknownFields != null) {");
+ writer.WriteLine(" this.UnknownFields = unknownFields.Build();");
+ writer.WriteLine("}");
+ }
+ writer.WriteLine("return this;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+
+ private void GenerateIsInitialized(TextGenerator writer)
+ {
+ writer.WriteLine("public override bool IsInitialized {");
+ writer.Indent();
+ writer.WriteLine("get {");
+ writer.Indent();
+
+ // Check that all required fields in this message are set.
+ // TODO(kenton): We can optimize this when we switch to putting all the
+ // "has" fields into a single bitfield.
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ if (field.IsRequired)
+ {
+ writer.WriteLine("if (!has{0}) return false;", field.CSharpOptions.PropertyName);
+ }
+ }
+
+ // Now check that all embedded messages are initialized.
+ foreach (FieldDescriptor field in Descriptor.Fields)
+ {
+ if (field.FieldType != FieldType.Message ||
+ !HasRequiredFields(field.MessageType, new Dictionary<MessageDescriptor, object>()))
+ {
+ continue;
+ }
+ string propertyName = NameHelpers.UnderscoresToPascalCase(GetFieldName(field));
+ if (field.IsRepeated)
+ {
+ writer.WriteLine("foreach ({0} element in {1}List) {{", GetClassName(field.MessageType),
+ propertyName);
+ writer.WriteLine(" if (!element.IsInitialized) return false;");
+ writer.WriteLine("}");
+ }
+ else if (field.IsOptional)
+ {
+ writer.WriteLine("if (Has{0}) {{", propertyName);
+ writer.WriteLine(" if (!{0}.IsInitialized) return false;", propertyName);
+ writer.WriteLine("}");
+ }
+ else
+ {
+ writer.WriteLine("if (!{0}.IsInitialized) return false;", propertyName);
+ }
+ }
+
+ if (Descriptor.Proto.ExtensionRangeCount > 0)
+ {
+ writer.WriteLine("if (!ExtensionsAreInitialized) return false;");
+ }
+ writer.WriteLine("return true;");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+
+ internal void GenerateExtensionRegistrationCode(TextGenerator writer)
+ {
+ foreach (FieldDescriptor extension in Descriptor.Extensions)
+ {
+ new ExtensionGenerator(extension).GenerateExtensionRegistrationCode(writer);
+ }
+ foreach (MessageDescriptor nestedMessage in Descriptor.NestedTypes)
+ {
+ new MessageGenerator(nestedMessage).GenerateExtensionRegistrationCode(writer);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/PluginProtoFile.cs b/csharp/src/ProtoGen/PluginProtoFile.cs
new file mode 100644
index 00000000..e0fed5c3
--- /dev/null
+++ b/csharp/src/ProtoGen/PluginProtoFile.cs
@@ -0,0 +1,1187 @@
+// Generated by protoc-gen-cs, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT!
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = global::Google.ProtocolBuffers;
+using pbc = global::Google.ProtocolBuffers.Collections;
+using pbd = global::Google.ProtocolBuffers.Descriptors;
+using scg = global::System.Collections.Generic;
+namespace Google.ProtocolBuffers.Compiler.PluginProto {
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class Plugin {
+
+ #region Extension registration
+ public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {
+ }
+ #endregion
+ #region Static variables
+ internal static pbd::MessageDescriptor internal__static_google_protobuf_compiler_CodeGeneratorRequest__Descriptor;
+ internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorRequest, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorRequest.Builder> internal__static_google_protobuf_compiler_CodeGeneratorRequest__FieldAccessorTable;
+ internal static pbd::MessageDescriptor internal__static_google_protobuf_compiler_CodeGeneratorResponse__Descriptor;
+ internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Builder> internal__static_google_protobuf_compiler_CodeGeneratorResponse__FieldAccessorTable;
+ internal static pbd::MessageDescriptor internal__static_google_protobuf_compiler_CodeGeneratorResponse_File__Descriptor;
+ internal static pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File.Builder> internal__static_google_protobuf_compiler_CodeGeneratorResponse_File__FieldAccessorTable;
+ #endregion
+ #region Descriptor
+ public static pbd::FileDescriptor Descriptor {
+ get { return descriptor; }
+ }
+ private static pbd::FileDescriptor descriptor;
+
+ static Plugin() {
+ byte[] descriptorData = global::System.Convert.FromBase64String(
+ string.Concat(
+ "CiVnb29nbGUvcHJvdG9idWYvY29tcGlsZXIvcGx1Z2luLnByb3RvEhhnb29n",
+ "bGUucHJvdG9idWYuY29tcGlsZXIaIGdvb2dsZS9wcm90b2J1Zi9kZXNjcmlw",
+ "dG9yLnByb3RvIn0KFENvZGVHZW5lcmF0b3JSZXF1ZXN0EhgKEGZpbGVfdG9f",
+ "Z2VuZXJhdGUYASADKAkSEQoJcGFyYW1ldGVyGAIgASgJEjgKCnByb3RvX2Zp",
+ "bGUYDyADKAsyJC5nb29nbGUucHJvdG9idWYuRmlsZURlc2NyaXB0b3JQcm90",
+ "byKqAQoVQ29kZUdlbmVyYXRvclJlc3BvbnNlEg0KBWVycm9yGAEgASgJEkIK",
+ "BGZpbGUYDyADKAsyNC5nb29nbGUucHJvdG9idWYuY29tcGlsZXIuQ29kZUdl",
+ "bmVyYXRvclJlc3BvbnNlLkZpbGUaPgoERmlsZRIMCgRuYW1lGAEgASgJEhcK",
+ "D2luc2VydGlvbl9wb2ludBgCIAEoCRIPCgdjb250ZW50GA8gASgJQiwKHGNv",
+ "bS5nb29nbGUucHJvdG9idWYuY29tcGlsZXJCDFBsdWdpblByb3Rvcw=="));
+ pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {
+ descriptor = root;
+ internal__static_google_protobuf_compiler_CodeGeneratorRequest__Descriptor = Descriptor.MessageTypes[0];
+ internal__static_google_protobuf_compiler_CodeGeneratorRequest__FieldAccessorTable =
+ new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorRequest, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorRequest.Builder>(internal__static_google_protobuf_compiler_CodeGeneratorRequest__Descriptor,
+ new string[] { "FileToGenerate", "Parameter", "ProtoFile", });
+ internal__static_google_protobuf_compiler_CodeGeneratorResponse__Descriptor = Descriptor.MessageTypes[1];
+ internal__static_google_protobuf_compiler_CodeGeneratorResponse__FieldAccessorTable =
+ new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Builder>(internal__static_google_protobuf_compiler_CodeGeneratorResponse__Descriptor,
+ new string[] { "Error", "File", });
+ internal__static_google_protobuf_compiler_CodeGeneratorResponse_File__Descriptor = internal__static_google_protobuf_compiler_CodeGeneratorResponse__Descriptor.NestedTypes[0];
+ internal__static_google_protobuf_compiler_CodeGeneratorResponse_File__FieldAccessorTable =
+ new pb::FieldAccess.FieldAccessorTable<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File.Builder>(internal__static_google_protobuf_compiler_CodeGeneratorResponse_File__Descriptor,
+ new string[] { "Name", "InsertionPoint", "Content", });
+ return null;
+ };
+ pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,
+ new pbd::FileDescriptor[] {
+ global::Google.ProtocolBuffers.DescriptorProtos.DescriptorProtoFile.Descriptor,
+ }, assigner);
+ }
+ #endregion
+
+ }
+ #region Messages
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class CodeGeneratorRequest : pb::GeneratedMessage<CodeGeneratorRequest, CodeGeneratorRequest.Builder> {
+ private CodeGeneratorRequest() { }
+ private static readonly CodeGeneratorRequest defaultInstance = new CodeGeneratorRequest().MakeReadOnly();
+ private static readonly string[] _codeGeneratorRequestFieldNames = new string[] { "file_to_generate", "parameter", "proto_file" };
+ private static readonly uint[] _codeGeneratorRequestFieldTags = new uint[] { 10, 18, 122 };
+ public static CodeGeneratorRequest DefaultInstance {
+ get { return defaultInstance; }
+ }
+
+ public override CodeGeneratorRequest DefaultInstanceForType {
+ get { return DefaultInstance; }
+ }
+
+ protected override CodeGeneratorRequest ThisMessage {
+ get { return this; }
+ }
+
+ public static pbd::MessageDescriptor Descriptor {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.internal__static_google_protobuf_compiler_CodeGeneratorRequest__Descriptor; }
+ }
+
+ protected override pb::FieldAccess.FieldAccessorTable<CodeGeneratorRequest, CodeGeneratorRequest.Builder> InternalFieldAccessors {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.internal__static_google_protobuf_compiler_CodeGeneratorRequest__FieldAccessorTable; }
+ }
+
+ public const int FileToGenerateFieldNumber = 1;
+ private pbc::PopsicleList<string> fileToGenerate_ = new pbc::PopsicleList<string>();
+ public scg::IList<string> FileToGenerateList {
+ get { return pbc::Lists.AsReadOnly(fileToGenerate_); }
+ }
+ public int FileToGenerateCount {
+ get { return fileToGenerate_.Count; }
+ }
+ public string GetFileToGenerate(int index) {
+ return fileToGenerate_[index];
+ }
+
+ public const int ParameterFieldNumber = 2;
+ private bool hasParameter;
+ private string parameter_ = "";
+ public bool HasParameter {
+ get { return hasParameter; }
+ }
+ public string Parameter {
+ get { return parameter_; }
+ }
+
+ public const int ProtoFileFieldNumber = 15;
+ private pbc::PopsicleList<global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto> protoFile_ = new pbc::PopsicleList<global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto>();
+ public scg::IList<global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto> ProtoFileList {
+ get { return protoFile_; }
+ }
+ public int ProtoFileCount {
+ get { return protoFile_.Count; }
+ }
+ public global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto GetProtoFile(int index) {
+ return protoFile_[index];
+ }
+
+ public override bool IsInitialized {
+ get {
+ foreach (global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto element in ProtoFileList) {
+ if (!element.IsInitialized) return false;
+ }
+ return true;
+ }
+ }
+
+ public override void WriteTo(pb::ICodedOutputStream output) {
+ int size = SerializedSize;
+ string[] field_names = _codeGeneratorRequestFieldNames;
+ if (fileToGenerate_.Count > 0) {
+ output.WriteStringArray(1, field_names[0], fileToGenerate_);
+ }
+ if (hasParameter) {
+ output.WriteString(2, field_names[1], Parameter);
+ }
+ if (protoFile_.Count > 0) {
+ output.WriteMessageArray(15, field_names[2], protoFile_);
+ }
+ UnknownFields.WriteTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public override int SerializedSize {
+ get {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ {
+ int dataSize = 0;
+ foreach (string element in FileToGenerateList) {
+ dataSize += pb::CodedOutputStream.ComputeStringSizeNoTag(element);
+ }
+ size += dataSize;
+ size += 1 * fileToGenerate_.Count;
+ }
+ if (hasParameter) {
+ size += pb::CodedOutputStream.ComputeStringSize(2, Parameter);
+ }
+ foreach (global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto element in ProtoFileList) {
+ size += pb::CodedOutputStream.ComputeMessageSize(15, element);
+ }
+ size += UnknownFields.SerializedSize;
+ memoizedSerializedSize = size;
+ return size;
+ }
+ }
+
+ public static CodeGeneratorRequest ParseFrom(pb::ByteString data) {
+ return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseFrom(byte[] data) {
+ return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseFrom(global::System.IO.Stream input) {
+ return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseDelimitedFrom(global::System.IO.Stream input) {
+ return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+ return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseFrom(pb::ICodedInputStream input) {
+ return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+ }
+ public static CodeGeneratorRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+ }
+ private CodeGeneratorRequest MakeReadOnly() {
+ fileToGenerate_.MakeReadOnly();
+ protoFile_.MakeReadOnly();
+ return this;
+ }
+
+ public static Builder CreateBuilder() { return new Builder(); }
+ public override Builder ToBuilder() { return CreateBuilder(this); }
+ public override Builder CreateBuilderForType() { return new Builder(); }
+ public static Builder CreateBuilder(CodeGeneratorRequest prototype) {
+ return new Builder(prototype);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class Builder : pb::GeneratedBuilder<CodeGeneratorRequest, Builder> {
+ protected override Builder ThisBuilder {
+ get { return this; }
+ }
+ public Builder() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ }
+ internal Builder(CodeGeneratorRequest cloneFrom) {
+ result = cloneFrom;
+ resultIsReadOnly = true;
+ }
+
+ private bool resultIsReadOnly;
+ private CodeGeneratorRequest result;
+
+ private CodeGeneratorRequest PrepareBuilder() {
+ if (resultIsReadOnly) {
+ CodeGeneratorRequest original = result;
+ result = new CodeGeneratorRequest();
+ resultIsReadOnly = false;
+ MergeFrom(original);
+ }
+ return result;
+ }
+
+ public override bool IsInitialized {
+ get { return result.IsInitialized; }
+ }
+
+ protected override CodeGeneratorRequest MessageBeingBuilt {
+ get { return PrepareBuilder(); }
+ }
+
+ public override Builder Clear() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ return this;
+ }
+
+ public override Builder Clone() {
+ if (resultIsReadOnly) {
+ return new Builder(result);
+ } else {
+ return new Builder().MergeFrom(result);
+ }
+ }
+
+ public override pbd::MessageDescriptor DescriptorForType {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorRequest.Descriptor; }
+ }
+
+ public override CodeGeneratorRequest DefaultInstanceForType {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorRequest.DefaultInstance; }
+ }
+
+ public override CodeGeneratorRequest BuildPartial() {
+ if (resultIsReadOnly) {
+ return result;
+ }
+ resultIsReadOnly = true;
+ return result.MakeReadOnly();
+ }
+
+ public override Builder MergeFrom(pb::IMessage other) {
+ if (other is CodeGeneratorRequest) {
+ return MergeFrom((CodeGeneratorRequest) other);
+ } else {
+ base.MergeFrom(other);
+ return this;
+ }
+ }
+
+ public override Builder MergeFrom(CodeGeneratorRequest other) {
+ if (other == global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorRequest.DefaultInstance) return this;
+ PrepareBuilder();
+ if (other.fileToGenerate_.Count != 0) {
+ result.fileToGenerate_.Add(other.fileToGenerate_);
+ }
+ if (other.HasParameter) {
+ Parameter = other.Parameter;
+ }
+ if (other.protoFile_.Count != 0) {
+ result.protoFile_.Add(other.protoFile_);
+ }
+ this.MergeUnknownFields(other.UnknownFields);
+ return this;
+ }
+
+ public override Builder MergeFrom(pb::ICodedInputStream input) {
+ return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ }
+
+ public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ PrepareBuilder();
+ pb::UnknownFieldSet.Builder unknownFields = null;
+ uint tag;
+ string field_name;
+ while (input.ReadTag(out tag, out field_name)) {
+ if(tag == 0 && field_name != null) {
+ int field_ordinal = global::System.Array.BinarySearch(_codeGeneratorRequestFieldNames, field_name, global::System.StringComparer.Ordinal);
+ if(field_ordinal >= 0)
+ tag = _codeGeneratorRequestFieldTags[field_ordinal];
+ else {
+ if (unknownFields == null) {
+ unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+ }
+ ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+ continue;
+ }
+ }
+ switch (tag) {
+ case 0: {
+ throw pb::InvalidProtocolBufferException.InvalidTag();
+ }
+ default: {
+ if (pb::WireFormat.IsEndGroupTag(tag)) {
+ if (unknownFields != null) {
+ this.UnknownFields = unknownFields.Build();
+ }
+ return this;
+ }
+ if (unknownFields == null) {
+ unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+ }
+ ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+ break;
+ }
+ case 10: {
+ input.ReadStringArray(tag, field_name, result.fileToGenerate_);
+ break;
+ }
+ case 18: {
+ result.hasParameter = input.ReadString(ref result.parameter_);
+ break;
+ }
+ case 122: {
+ input.ReadMessageArray(tag, field_name, result.protoFile_, global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto.DefaultInstance, extensionRegistry);
+ break;
+ }
+ }
+ }
+
+ if (unknownFields != null) {
+ this.UnknownFields = unknownFields.Build();
+ }
+ return this;
+ }
+
+
+ public pbc::IPopsicleList<string> FileToGenerateList {
+ get { return PrepareBuilder().fileToGenerate_; }
+ }
+ public int FileToGenerateCount {
+ get { return result.FileToGenerateCount; }
+ }
+ public string GetFileToGenerate(int index) {
+ return result.GetFileToGenerate(index);
+ }
+ public Builder SetFileToGenerate(int index, string value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.fileToGenerate_[index] = value;
+ return this;
+ }
+ public Builder AddFileToGenerate(string value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.fileToGenerate_.Add(value);
+ return this;
+ }
+ public Builder AddRangeFileToGenerate(scg::IEnumerable<string> values) {
+ PrepareBuilder();
+ result.fileToGenerate_.Add(values);
+ return this;
+ }
+ public Builder ClearFileToGenerate() {
+ PrepareBuilder();
+ result.fileToGenerate_.Clear();
+ return this;
+ }
+
+ public bool HasParameter {
+ get { return result.hasParameter; }
+ }
+ public string Parameter {
+ get { return result.Parameter; }
+ set { SetParameter(value); }
+ }
+ public Builder SetParameter(string value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.hasParameter = true;
+ result.parameter_ = value;
+ return this;
+ }
+ public Builder ClearParameter() {
+ PrepareBuilder();
+ result.hasParameter = false;
+ result.parameter_ = "";
+ return this;
+ }
+
+ public pbc::IPopsicleList<global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto> ProtoFileList {
+ get { return PrepareBuilder().protoFile_; }
+ }
+ public int ProtoFileCount {
+ get { return result.ProtoFileCount; }
+ }
+ public global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto GetProtoFile(int index) {
+ return result.GetProtoFile(index);
+ }
+ public Builder SetProtoFile(int index, global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.protoFile_[index] = value;
+ return this;
+ }
+ public Builder SetProtoFile(int index, global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto.Builder builderForValue) {
+ pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+ PrepareBuilder();
+ result.protoFile_[index] = builderForValue.Build();
+ return this;
+ }
+ public Builder AddProtoFile(global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.protoFile_.Add(value);
+ return this;
+ }
+ public Builder AddProtoFile(global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto.Builder builderForValue) {
+ pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+ PrepareBuilder();
+ result.protoFile_.Add(builderForValue.Build());
+ return this;
+ }
+ public Builder AddRangeProtoFile(scg::IEnumerable<global::Google.ProtocolBuffers.DescriptorProtos.FileDescriptorProto> values) {
+ PrepareBuilder();
+ result.protoFile_.Add(values);
+ return this;
+ }
+ public Builder ClearProtoFile() {
+ PrepareBuilder();
+ result.protoFile_.Clear();
+ return this;
+ }
+ }
+ static CodeGeneratorRequest() {
+ object.ReferenceEquals(global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.Descriptor, null);
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class CodeGeneratorResponse : pb::GeneratedMessage<CodeGeneratorResponse, CodeGeneratorResponse.Builder> {
+ private CodeGeneratorResponse() { }
+ private static readonly CodeGeneratorResponse defaultInstance = new CodeGeneratorResponse().MakeReadOnly();
+ private static readonly string[] _codeGeneratorResponseFieldNames = new string[] { "error", "file" };
+ private static readonly uint[] _codeGeneratorResponseFieldTags = new uint[] { 10, 122 };
+ public static CodeGeneratorResponse DefaultInstance {
+ get { return defaultInstance; }
+ }
+
+ public override CodeGeneratorResponse DefaultInstanceForType {
+ get { return DefaultInstance; }
+ }
+
+ protected override CodeGeneratorResponse ThisMessage {
+ get { return this; }
+ }
+
+ public static pbd::MessageDescriptor Descriptor {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.internal__static_google_protobuf_compiler_CodeGeneratorResponse__Descriptor; }
+ }
+
+ protected override pb::FieldAccess.FieldAccessorTable<CodeGeneratorResponse, CodeGeneratorResponse.Builder> InternalFieldAccessors {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.internal__static_google_protobuf_compiler_CodeGeneratorResponse__FieldAccessorTable; }
+ }
+
+ #region Nested types
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public static partial class Types {
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class File : pb::GeneratedMessage<File, File.Builder> {
+ private File() { }
+ private static readonly File defaultInstance = new File().MakeReadOnly();
+ private static readonly string[] _fileFieldNames = new string[] { "content", "insertion_point", "name" };
+ private static readonly uint[] _fileFieldTags = new uint[] { 122, 18, 10 };
+ public static File DefaultInstance {
+ get { return defaultInstance; }
+ }
+
+ public override File DefaultInstanceForType {
+ get { return DefaultInstance; }
+ }
+
+ protected override File ThisMessage {
+ get { return this; }
+ }
+
+ public static pbd::MessageDescriptor Descriptor {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.internal__static_google_protobuf_compiler_CodeGeneratorResponse_File__Descriptor; }
+ }
+
+ protected override pb::FieldAccess.FieldAccessorTable<File, File.Builder> InternalFieldAccessors {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.internal__static_google_protobuf_compiler_CodeGeneratorResponse_File__FieldAccessorTable; }
+ }
+
+ public const int NameFieldNumber = 1;
+ private bool hasName;
+ private string name_ = "";
+ public bool HasName {
+ get { return hasName; }
+ }
+ public string Name {
+ get { return name_; }
+ }
+
+ public const int InsertionPointFieldNumber = 2;
+ private bool hasInsertionPoint;
+ private string insertionPoint_ = "";
+ public bool HasInsertionPoint {
+ get { return hasInsertionPoint; }
+ }
+ public string InsertionPoint {
+ get { return insertionPoint_; }
+ }
+
+ public const int ContentFieldNumber = 15;
+ private bool hasContent;
+ private string content_ = "";
+ public bool HasContent {
+ get { return hasContent; }
+ }
+ public string Content {
+ get { return content_; }
+ }
+
+ public override bool IsInitialized {
+ get {
+ return true;
+ }
+ }
+
+ public override void WriteTo(pb::ICodedOutputStream output) {
+ int size = SerializedSize;
+ string[] field_names = _fileFieldNames;
+ if (hasName) {
+ output.WriteString(1, field_names[2], Name);
+ }
+ if (hasInsertionPoint) {
+ output.WriteString(2, field_names[1], InsertionPoint);
+ }
+ if (hasContent) {
+ output.WriteString(15, field_names[0], Content);
+ }
+ UnknownFields.WriteTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public override int SerializedSize {
+ get {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (hasName) {
+ size += pb::CodedOutputStream.ComputeStringSize(1, Name);
+ }
+ if (hasInsertionPoint) {
+ size += pb::CodedOutputStream.ComputeStringSize(2, InsertionPoint);
+ }
+ if (hasContent) {
+ size += pb::CodedOutputStream.ComputeStringSize(15, Content);
+ }
+ size += UnknownFields.SerializedSize;
+ memoizedSerializedSize = size;
+ return size;
+ }
+ }
+
+ public static File ParseFrom(pb::ByteString data) {
+ return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+ }
+ public static File ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+ }
+ public static File ParseFrom(byte[] data) {
+ return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+ }
+ public static File ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+ }
+ public static File ParseFrom(global::System.IO.Stream input) {
+ return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+ }
+ public static File ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+ }
+ public static File ParseDelimitedFrom(global::System.IO.Stream input) {
+ return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+ }
+ public static File ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+ return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+ }
+ public static File ParseFrom(pb::ICodedInputStream input) {
+ return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+ }
+ public static File ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+ }
+ private File MakeReadOnly() {
+ return this;
+ }
+
+ public static Builder CreateBuilder() { return new Builder(); }
+ public override Builder ToBuilder() { return CreateBuilder(this); }
+ public override Builder CreateBuilderForType() { return new Builder(); }
+ public static Builder CreateBuilder(File prototype) {
+ return new Builder(prototype);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class Builder : pb::GeneratedBuilder<File, Builder> {
+ protected override Builder ThisBuilder {
+ get { return this; }
+ }
+ public Builder() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ }
+ internal Builder(File cloneFrom) {
+ result = cloneFrom;
+ resultIsReadOnly = true;
+ }
+
+ private bool resultIsReadOnly;
+ private File result;
+
+ private File PrepareBuilder() {
+ if (resultIsReadOnly) {
+ File original = result;
+ result = new File();
+ resultIsReadOnly = false;
+ MergeFrom(original);
+ }
+ return result;
+ }
+
+ public override bool IsInitialized {
+ get { return result.IsInitialized; }
+ }
+
+ protected override File MessageBeingBuilt {
+ get { return PrepareBuilder(); }
+ }
+
+ public override Builder Clear() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ return this;
+ }
+
+ public override Builder Clone() {
+ if (resultIsReadOnly) {
+ return new Builder(result);
+ } else {
+ return new Builder().MergeFrom(result);
+ }
+ }
+
+ public override pbd::MessageDescriptor DescriptorForType {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File.Descriptor; }
+ }
+
+ public override File DefaultInstanceForType {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File.DefaultInstance; }
+ }
+
+ public override File BuildPartial() {
+ if (resultIsReadOnly) {
+ return result;
+ }
+ resultIsReadOnly = true;
+ return result.MakeReadOnly();
+ }
+
+ public override Builder MergeFrom(pb::IMessage other) {
+ if (other is File) {
+ return MergeFrom((File) other);
+ } else {
+ base.MergeFrom(other);
+ return this;
+ }
+ }
+
+ public override Builder MergeFrom(File other) {
+ if (other == global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File.DefaultInstance) return this;
+ PrepareBuilder();
+ if (other.HasName) {
+ Name = other.Name;
+ }
+ if (other.HasInsertionPoint) {
+ InsertionPoint = other.InsertionPoint;
+ }
+ if (other.HasContent) {
+ Content = other.Content;
+ }
+ this.MergeUnknownFields(other.UnknownFields);
+ return this;
+ }
+
+ public override Builder MergeFrom(pb::ICodedInputStream input) {
+ return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ }
+
+ public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ PrepareBuilder();
+ pb::UnknownFieldSet.Builder unknownFields = null;
+ uint tag;
+ string field_name;
+ while (input.ReadTag(out tag, out field_name)) {
+ if(tag == 0 && field_name != null) {
+ int field_ordinal = global::System.Array.BinarySearch(_fileFieldNames, field_name, global::System.StringComparer.Ordinal);
+ if(field_ordinal >= 0)
+ tag = _fileFieldTags[field_ordinal];
+ else {
+ if (unknownFields == null) {
+ unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+ }
+ ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+ continue;
+ }
+ }
+ switch (tag) {
+ case 0: {
+ throw pb::InvalidProtocolBufferException.InvalidTag();
+ }
+ default: {
+ if (pb::WireFormat.IsEndGroupTag(tag)) {
+ if (unknownFields != null) {
+ this.UnknownFields = unknownFields.Build();
+ }
+ return this;
+ }
+ if (unknownFields == null) {
+ unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+ }
+ ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+ break;
+ }
+ case 10: {
+ result.hasName = input.ReadString(ref result.name_);
+ break;
+ }
+ case 18: {
+ result.hasInsertionPoint = input.ReadString(ref result.insertionPoint_);
+ break;
+ }
+ case 122: {
+ result.hasContent = input.ReadString(ref result.content_);
+ break;
+ }
+ }
+ }
+
+ if (unknownFields != null) {
+ this.UnknownFields = unknownFields.Build();
+ }
+ return this;
+ }
+
+
+ public bool HasName {
+ get { return result.hasName; }
+ }
+ public string Name {
+ get { return result.Name; }
+ set { SetName(value); }
+ }
+ public Builder SetName(string value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.hasName = true;
+ result.name_ = value;
+ return this;
+ }
+ public Builder ClearName() {
+ PrepareBuilder();
+ result.hasName = false;
+ result.name_ = "";
+ return this;
+ }
+
+ public bool HasInsertionPoint {
+ get { return result.hasInsertionPoint; }
+ }
+ public string InsertionPoint {
+ get { return result.InsertionPoint; }
+ set { SetInsertionPoint(value); }
+ }
+ public Builder SetInsertionPoint(string value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.hasInsertionPoint = true;
+ result.insertionPoint_ = value;
+ return this;
+ }
+ public Builder ClearInsertionPoint() {
+ PrepareBuilder();
+ result.hasInsertionPoint = false;
+ result.insertionPoint_ = "";
+ return this;
+ }
+
+ public bool HasContent {
+ get { return result.hasContent; }
+ }
+ public string Content {
+ get { return result.Content; }
+ set { SetContent(value); }
+ }
+ public Builder SetContent(string value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.hasContent = true;
+ result.content_ = value;
+ return this;
+ }
+ public Builder ClearContent() {
+ PrepareBuilder();
+ result.hasContent = false;
+ result.content_ = "";
+ return this;
+ }
+ }
+ static File() {
+ object.ReferenceEquals(global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.Descriptor, null);
+ }
+ }
+
+ }
+ #endregion
+
+ public const int ErrorFieldNumber = 1;
+ private bool hasError;
+ private string error_ = "";
+ public bool HasError {
+ get { return hasError; }
+ }
+ public string Error {
+ get { return error_; }
+ }
+
+ public const int FileFieldNumber = 15;
+ private pbc::PopsicleList<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File> file_ = new pbc::PopsicleList<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File>();
+ public scg::IList<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File> FileList {
+ get { return file_; }
+ }
+ public int FileCount {
+ get { return file_.Count; }
+ }
+ public global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File GetFile(int index) {
+ return file_[index];
+ }
+
+ public override bool IsInitialized {
+ get {
+ return true;
+ }
+ }
+
+ public override void WriteTo(pb::ICodedOutputStream output) {
+ int size = SerializedSize;
+ string[] field_names = _codeGeneratorResponseFieldNames;
+ if (hasError) {
+ output.WriteString(1, field_names[0], Error);
+ }
+ if (file_.Count > 0) {
+ output.WriteMessageArray(15, field_names[1], file_);
+ }
+ UnknownFields.WriteTo(output);
+ }
+
+ private int memoizedSerializedSize = -1;
+ public override int SerializedSize {
+ get {
+ int size = memoizedSerializedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (hasError) {
+ size += pb::CodedOutputStream.ComputeStringSize(1, Error);
+ }
+ foreach (global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File element in FileList) {
+ size += pb::CodedOutputStream.ComputeMessageSize(15, element);
+ }
+ size += UnknownFields.SerializedSize;
+ memoizedSerializedSize = size;
+ return size;
+ }
+ }
+
+ public static CodeGeneratorResponse ParseFrom(pb::ByteString data) {
+ return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseFrom(byte[] data) {
+ return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseFrom(global::System.IO.Stream input) {
+ return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseDelimitedFrom(global::System.IO.Stream input) {
+ return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {
+ return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseFrom(pb::ICodedInputStream input) {
+ return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();
+ }
+ public static CodeGeneratorResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();
+ }
+ private CodeGeneratorResponse MakeReadOnly() {
+ file_.MakeReadOnly();
+ return this;
+ }
+
+ public static Builder CreateBuilder() { return new Builder(); }
+ public override Builder ToBuilder() { return CreateBuilder(this); }
+ public override Builder CreateBuilderForType() { return new Builder(); }
+ public static Builder CreateBuilder(CodeGeneratorResponse prototype) {
+ return new Builder(prototype);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ public sealed partial class Builder : pb::GeneratedBuilder<CodeGeneratorResponse, Builder> {
+ protected override Builder ThisBuilder {
+ get { return this; }
+ }
+ public Builder() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ }
+ internal Builder(CodeGeneratorResponse cloneFrom) {
+ result = cloneFrom;
+ resultIsReadOnly = true;
+ }
+
+ private bool resultIsReadOnly;
+ private CodeGeneratorResponse result;
+
+ private CodeGeneratorResponse PrepareBuilder() {
+ if (resultIsReadOnly) {
+ CodeGeneratorResponse original = result;
+ result = new CodeGeneratorResponse();
+ resultIsReadOnly = false;
+ MergeFrom(original);
+ }
+ return result;
+ }
+
+ public override bool IsInitialized {
+ get { return result.IsInitialized; }
+ }
+
+ protected override CodeGeneratorResponse MessageBeingBuilt {
+ get { return PrepareBuilder(); }
+ }
+
+ public override Builder Clear() {
+ result = DefaultInstance;
+ resultIsReadOnly = true;
+ return this;
+ }
+
+ public override Builder Clone() {
+ if (resultIsReadOnly) {
+ return new Builder(result);
+ } else {
+ return new Builder().MergeFrom(result);
+ }
+ }
+
+ public override pbd::MessageDescriptor DescriptorForType {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Descriptor; }
+ }
+
+ public override CodeGeneratorResponse DefaultInstanceForType {
+ get { return global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.DefaultInstance; }
+ }
+
+ public override CodeGeneratorResponse BuildPartial() {
+ if (resultIsReadOnly) {
+ return result;
+ }
+ resultIsReadOnly = true;
+ return result.MakeReadOnly();
+ }
+
+ public override Builder MergeFrom(pb::IMessage other) {
+ if (other is CodeGeneratorResponse) {
+ return MergeFrom((CodeGeneratorResponse) other);
+ } else {
+ base.MergeFrom(other);
+ return this;
+ }
+ }
+
+ public override Builder MergeFrom(CodeGeneratorResponse other) {
+ if (other == global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.DefaultInstance) return this;
+ PrepareBuilder();
+ if (other.HasError) {
+ Error = other.Error;
+ }
+ if (other.file_.Count != 0) {
+ result.file_.Add(other.file_);
+ }
+ this.MergeUnknownFields(other.UnknownFields);
+ return this;
+ }
+
+ public override Builder MergeFrom(pb::ICodedInputStream input) {
+ return MergeFrom(input, pb::ExtensionRegistry.Empty);
+ }
+
+ public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {
+ PrepareBuilder();
+ pb::UnknownFieldSet.Builder unknownFields = null;
+ uint tag;
+ string field_name;
+ while (input.ReadTag(out tag, out field_name)) {
+ if(tag == 0 && field_name != null) {
+ int field_ordinal = global::System.Array.BinarySearch(_codeGeneratorResponseFieldNames, field_name, global::System.StringComparer.Ordinal);
+ if(field_ordinal >= 0)
+ tag = _codeGeneratorResponseFieldTags[field_ordinal];
+ else {
+ if (unknownFields == null) {
+ unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+ }
+ ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+ continue;
+ }
+ }
+ switch (tag) {
+ case 0: {
+ throw pb::InvalidProtocolBufferException.InvalidTag();
+ }
+ default: {
+ if (pb::WireFormat.IsEndGroupTag(tag)) {
+ if (unknownFields != null) {
+ this.UnknownFields = unknownFields.Build();
+ }
+ return this;
+ }
+ if (unknownFields == null) {
+ unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);
+ }
+ ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name);
+ break;
+ }
+ case 10: {
+ result.hasError = input.ReadString(ref result.error_);
+ break;
+ }
+ case 122: {
+ input.ReadMessageArray(tag, field_name, result.file_, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File.DefaultInstance, extensionRegistry);
+ break;
+ }
+ }
+ }
+
+ if (unknownFields != null) {
+ this.UnknownFields = unknownFields.Build();
+ }
+ return this;
+ }
+
+
+ public bool HasError {
+ get { return result.hasError; }
+ }
+ public string Error {
+ get { return result.Error; }
+ set { SetError(value); }
+ }
+ public Builder SetError(string value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.hasError = true;
+ result.error_ = value;
+ return this;
+ }
+ public Builder ClearError() {
+ PrepareBuilder();
+ result.hasError = false;
+ result.error_ = "";
+ return this;
+ }
+
+ public pbc::IPopsicleList<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File> FileList {
+ get { return PrepareBuilder().file_; }
+ }
+ public int FileCount {
+ get { return result.FileCount; }
+ }
+ public global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File GetFile(int index) {
+ return result.GetFile(index);
+ }
+ public Builder SetFile(int index, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.file_[index] = value;
+ return this;
+ }
+ public Builder SetFile(int index, global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File.Builder builderForValue) {
+ pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+ PrepareBuilder();
+ result.file_[index] = builderForValue.Build();
+ return this;
+ }
+ public Builder AddFile(global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File value) {
+ pb::ThrowHelper.ThrowIfNull(value, "value");
+ PrepareBuilder();
+ result.file_.Add(value);
+ return this;
+ }
+ public Builder AddFile(global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File.Builder builderForValue) {
+ pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue");
+ PrepareBuilder();
+ result.file_.Add(builderForValue.Build());
+ return this;
+ }
+ public Builder AddRangeFile(scg::IEnumerable<global::Google.ProtocolBuffers.Compiler.PluginProto.CodeGeneratorResponse.Types.File> values) {
+ PrepareBuilder();
+ result.file_.Add(values);
+ return this;
+ }
+ public Builder ClearFile() {
+ PrepareBuilder();
+ result.file_.Clear();
+ return this;
+ }
+ }
+ static CodeGeneratorResponse() {
+ object.ReferenceEquals(global::Google.ProtocolBuffers.Compiler.PluginProto.Plugin.Descriptor, null);
+ }
+ }
+
+ #endregion
+
+}
+
+#endregion Designer generated code
diff --git a/csharp/src/ProtoGen/PrimitiveFieldGenerator.cs b/csharp/src/ProtoGen/PrimitiveFieldGenerator.cs
new file mode 100644
index 00000000..69e0d4d9
--- /dev/null
+++ b/csharp/src/ProtoGen/PrimitiveFieldGenerator.cs
@@ -0,0 +1,140 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ // TODO(jonskeet): Refactor this. There's loads of common code here.
+ internal class PrimitiveFieldGenerator : FieldGeneratorBase, IFieldSourceGenerator
+ {
+ internal PrimitiveFieldGenerator(FieldDescriptor descriptor, int fieldOrdinal)
+ : base(descriptor, fieldOrdinal)
+ {
+ }
+
+ public void GenerateMembers(TextGenerator writer)
+ {
+ writer.WriteLine("private bool has{0};", PropertyName);
+ writer.WriteLine("private {0} {1}_{2};", TypeName, Name, HasDefaultValue ? " = " + DefaultValue : "");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public bool Has{0} {{", PropertyName);
+ writer.WriteLine(" get {{ return has{0}; }}", PropertyName);
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return {0}_; }}", Name);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuilderMembers(TextGenerator writer)
+ {
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public bool Has{0} {{", PropertyName);
+ writer.WriteLine(" get {{ return result.has{0}; }}", PropertyName);
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public {0} {1} {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return result.{0}; }}", PropertyName);
+ writer.WriteLine(" set {{ Set{0}(value); }}", PropertyName);
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public Builder Set{0}({1} value) {{", PropertyName, TypeName);
+ AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.has{0} = true;", PropertyName);
+ writer.WriteLine(" result.{0}_ = value;", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.has{0} = false;", PropertyName);
+ writer.WriteLine(" result.{0}_ = {1};", Name, DefaultValue);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ }
+
+ public void GenerateMergingCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (other.Has{0}) {{", PropertyName);
+ writer.WriteLine(" {0} = other.{0};", PropertyName);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuildingCode(TextGenerator writer)
+ {
+ // Nothing to do here for primitive types
+ }
+
+ public void GenerateParsingCode(TextGenerator writer)
+ {
+ writer.WriteLine("result.has{0} = input.Read{1}(ref result.{2}_);", PropertyName, CapitalizedTypeName, Name);
+ }
+
+ public void GenerateSerializationCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) {{", PropertyName);
+ writer.WriteLine(" output.Write{0}({1}, field_names[{3}], {2});", CapitalizedTypeName, Number, PropertyName,
+ FieldOrdinal);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateSerializedSizeCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) {{", PropertyName);
+ writer.WriteLine(" size += pb::CodedOutputStream.Compute{0}Size({1}, {2});",
+ CapitalizedTypeName, Number, PropertyName);
+ writer.WriteLine("}");
+ }
+
+ public override void WriteHash(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0}) hash ^= {1}_.GetHashCode();", PropertyName, Name);
+ }
+
+ public override void WriteEquals(TextGenerator writer)
+ {
+ writer.WriteLine("if (has{0} != other.has{0} || (has{0} && !{1}_.Equals(other.{1}_))) return false;",
+ PropertyName, Name);
+ }
+
+ public override void WriteToString(TextGenerator writer)
+ {
+ writer.WriteLine("PrintField(\"{0}\", has{1}, {2}_, writer);", Descriptor.Name, PropertyName, Name);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/Program.cs b/csharp/src/ProtoGen/Program.cs
new file mode 100644
index 00000000..b11d32e0
--- /dev/null
+++ b/csharp/src/ProtoGen/Program.cs
@@ -0,0 +1,105 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using Google.ProtocolBuffers.Compiler.PluginProto;
+using Google.ProtocolBuffers.DescriptorProtos;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// Entry point for the Protocol Buffers generator.
+ /// </summary>
+ internal class Program
+ {
+ internal static int Main(string[] args)
+ {
+ try
+ {
+ // Hack to make sure everything's initialized
+ DescriptorProtoFile.Descriptor.ToString();
+ GeneratorOptions options = new GeneratorOptions {Arguments = args};
+
+ IList<string> validationFailures;
+ if (!options.TryValidate(out validationFailures))
+ {
+ // We've already got the message-building logic in the exception...
+ InvalidOptionsException exception = new InvalidOptionsException(validationFailures);
+ Console.WriteLine(exception.Message);
+ return 1;
+ }
+
+ var request = new CodeGeneratorRequest.Builder();
+ foreach (string inputFile in options.InputFiles)
+ {
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
+ CSharpOptions.RegisterAllExtensions(extensionRegistry);
+ using (Stream inputStream = File.OpenRead(inputFile))
+ {
+ var fileSet = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry);
+ foreach (var fileProto in fileSet.FileList)
+ {
+ request.AddFileToGenerate(fileProto.Name);
+ request.AddProtoFile(fileProto);
+ }
+ }
+ }
+
+ Generator generator = Generator.CreateGenerator(options);
+ var response = new CodeGeneratorResponse.Builder();
+ generator.Generate(request.Build(), response);
+ if (response.HasError)
+ {
+ throw new Exception(response.Error);
+ }
+ foreach (var file in response.FileList)
+ {
+ File.WriteAllText(file.Name, file.Content);
+ }
+ return 0;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine("Error: {0}", e.Message);
+ Console.Error.WriteLine();
+ Console.Error.WriteLine("Detailed exception information: {0}", e);
+ return 1;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/ProgramPreprocess.cs b/csharp/src/ProtoGen/ProgramPreprocess.cs
new file mode 100644
index 00000000..343e1f2a
--- /dev/null
+++ b/csharp/src/ProtoGen/ProgramPreprocess.cs
@@ -0,0 +1,276 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// Preprocesses any input files with an extension of '.proto' by running protoc.exe. If arguments
+ /// are supplied with '--' prefix they are provided to protoc.exe, otherwise they are assumed to
+ /// be used for ProtoGen.exe which is run on the resulting output proto buffer. If the option
+ /// --descriptor_set_out= is specified the proto buffer file is kept, otherwise it will be removed
+ /// after code generation.
+ /// </summary>
+ public class ProgramPreprocess
+ {
+ private const string ProtocExecutable = "protoc.exe";
+ private const string ProtocDirectoryArg = "--protoc_dir=";
+
+ private static int Main(string[] args)
+ {
+ try
+ {
+ return Environment.ExitCode = Run(args);
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine(ex);
+ return Environment.ExitCode = 2;
+ }
+ }
+
+ public static int Run(params string[] args)
+ {
+ bool deleteFile = false;
+ string tempFile = null;
+ int result;
+ bool doHelp = args.Length == 0;
+ try
+ {
+ List<string> protocArgs = new List<string>();
+ List<string> protoGenArgs = new List<string>();
+
+ string protocFile = GuessProtocFile(args);
+
+ foreach (string arg in args)
+ {
+ doHelp |= StringComparer.OrdinalIgnoreCase.Equals(arg, "/?");
+ doHelp |= StringComparer.OrdinalIgnoreCase.Equals(arg, "/help");
+ doHelp |= StringComparer.OrdinalIgnoreCase.Equals(arg, "-?");
+ doHelp |= StringComparer.OrdinalIgnoreCase.Equals(arg, "-help");
+
+ if (arg.StartsWith("--descriptor_set_out="))
+ {
+ tempFile = arg.Substring("--descriptor_set_out=".Length);
+ protoGenArgs.Add(tempFile);
+ }
+ }
+
+ if (doHelp)
+ {
+ Console.WriteLine();
+ Console.WriteLine("PROTOC.exe: Use any of the following options that begin with '--':");
+ Console.WriteLine();
+ try
+ {
+ RunProtoc(protocFile, "--help");
+ }
+ catch (Exception ex)
+ {
+ Console.Error.WriteLine(ex.Message);
+ }
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine(
+ "PROTOGEN.exe: The following options are used to specify defaults for code generation.");
+ Console.WriteLine();
+ Program.Main(new string[0]);
+ Console.WriteLine();
+ Console.WriteLine("The following option enables PROTOGEN.exe to find PROTOC.exe");
+ Console.WriteLine("{0}<directory containing protoc.exe>", ProtocDirectoryArg);
+ return 0;
+ }
+
+ string pathRoot = Environment.CurrentDirectory;
+ foreach(string arg in args)
+ {
+ if (arg.StartsWith("--proto_path=", StringComparison.InvariantCultureIgnoreCase))
+ {
+ pathRoot = arg.Substring(13);
+ }
+ }
+
+ foreach (string arg in args)
+ {
+ if (arg.StartsWith(ProtocDirectoryArg))
+ {
+ // Handled earlier
+ continue;
+ }
+ if (arg.StartsWith("--"))
+ {
+ protocArgs.Add(arg);
+ }
+ else if ((File.Exists(arg) || File.Exists(Path.Combine(pathRoot, arg))) &&
+ StringComparer.OrdinalIgnoreCase.Equals(".proto", Path.GetExtension(arg)))
+ {
+ if (tempFile == null)
+ {
+ deleteFile = true;
+ tempFile = Path.GetTempFileName();
+ protocArgs.Add(String.Format("--descriptor_set_out={0}", tempFile));
+ protoGenArgs.Add(tempFile);
+ }
+ string patharg = arg;
+ if (!File.Exists(patharg))
+ {
+ patharg = Path.Combine(pathRoot, arg);
+ }
+
+ protocArgs.Add(patharg);
+ }
+ else
+ {
+ protoGenArgs.Add(arg);
+ }
+ }
+
+ if (tempFile != null)
+ {
+ result = RunProtoc(protocFile, protocArgs.ToArray());
+ if (result != 0)
+ {
+ return result;
+ }
+ }
+
+ result = Program.Main(protoGenArgs.ToArray());
+ }
+ finally
+ {
+ if (deleteFile && tempFile != null && File.Exists(tempFile))
+ {
+ File.Delete(tempFile);
+ }
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Tries to work out where protoc is based on command line arguments, the current
+ /// directory, the directory containing protogen, and the path.
+ /// </summary>
+ /// <returns>The path to protoc.exe, or null if it can't be found.</returns>
+ private static string GuessProtocFile(params string[] args)
+ {
+ // Why oh why is this not in System.IO.Path or Environment...?
+ List<string> searchPath = new List<string>();
+ foreach (string arg in args)
+ {
+ if (arg.StartsWith("--protoc_dir="))
+ {
+ searchPath.Add(arg.Substring(ProtocDirectoryArg.Length));
+ }
+ }
+ searchPath.Add(Environment.CurrentDirectory);
+ searchPath.Add(AppDomain.CurrentDomain.BaseDirectory);
+ searchPath.AddRange((Environment.GetEnvironmentVariable("PATH") ?? String.Empty).Split(Path.PathSeparator));
+
+ foreach (string path in searchPath)
+ {
+ string exeFile = Path.Combine(path, ProtocExecutable);
+ if (File.Exists(exeFile))
+ {
+ return exeFile;
+ }
+ }
+ return null;
+ }
+
+ private static int RunProtoc(string exeFile, params string[] args)
+ {
+ if (exeFile == null)
+ {
+ throw new FileNotFoundException(
+ "Unable to locate " + ProtocExecutable +
+ " make sure it is in the PATH, cwd, or exe dir, or use --protoc_dir=...");
+ }
+
+ ProcessStartInfo psi = new ProcessStartInfo(exeFile);
+ psi.Arguments = EscapeArguments(args);
+ psi.RedirectStandardError = true;
+ psi.RedirectStandardInput = false;
+ psi.RedirectStandardOutput = true;
+ psi.ErrorDialog = false;
+ psi.CreateNoWindow = true;
+ psi.UseShellExecute = false;
+ psi.WorkingDirectory = Environment.CurrentDirectory;
+
+ Process process = Process.Start(psi);
+ if (process == null)
+ {
+ return 1;
+ }
+
+ process.WaitForExit();
+
+ string tmp = process.StandardOutput.ReadToEnd();
+ if (tmp.Trim().Length > 0)
+ {
+ Console.Out.WriteLine(tmp);
+ }
+ tmp = process.StandardError.ReadToEnd();
+ if (tmp.Trim().Length > 0)
+ {
+ // Replace protoc output with something more amenable to Visual Studio.
+ var regexMsvs = new Regex(@"(.*)\((\d+)\).* column=(\d+)\s*:\s*(.*)");
+ tmp = regexMsvs.Replace(tmp, "$1($2,$3): error CS9999: $4");
+ var regexGcc = new Regex(@"(.*):(\d+):(\d+):\s*(.*)");
+ tmp = regexGcc.Replace(tmp, "$1($2,$3): error CS9999: $4");
+ Console.Error.WriteLine(tmp);
+ }
+ return process.ExitCode;
+ }
+
+ /// <summary>
+ /// Quotes all arguments that contain whitespace, or begin with a quote and returns a single
+ /// argument string for use with Process.Start().
+ /// </summary>
+ /// <remarks>http://csharptest.net/?p=529</remarks>
+ /// <param name="args">A list of strings for arguments, may not contain null, '\0', '\r', or '\n'</param>
+ /// <returns>The combined list of escaped/quoted strings</returns>
+ /// <exception cref="System.ArgumentNullException">Raised when one of the arguments is null</exception>
+ /// <exception cref="System.ArgumentOutOfRangeException">Raised if an argument contains '\0', '\r', or '\n'</exception>
+ public static string EscapeArguments(params string[] args)
+ {
+ StringBuilder arguments = new StringBuilder();
+ Regex invalidChar = new Regex("[\x00\x0a\x0d]");// these can not be escaped
+ Regex needsQuotes = new Regex(@"\s|""");// contains whitespace or two quote characters
+ Regex escapeQuote = new Regex(@"(\\*)(""|$)");// one or more '\' followed with a quote or end of string
+ for (int carg = 0; args != null && carg < args.Length; carg++)
+ {
+ if (args[carg] == null)
+ {
+ throw new ArgumentNullException("args[" + carg + "]");
+ }
+ if (invalidChar.IsMatch(args[carg]))
+ {
+ throw new ArgumentOutOfRangeException("args[" + carg + "]");
+ }
+ if (args[carg] == String.Empty)
+ {
+ arguments.Append("\"\"");
+ }
+ else if (!needsQuotes.IsMatch(args[carg])) { arguments.Append(args[carg]); }
+ else
+ {
+ arguments.Append('"');
+ arguments.Append(escapeQuote.Replace(args[carg],
+ m =>
+ m.Groups[1].Value + m.Groups[1].Value +
+ (m.Groups[2].Value == "\"" ? "\\\"" : "")
+ ));
+ arguments.Append('"');
+ }
+ if (carg + 1 < args.Length)
+ {
+ arguments.Append(' ');
+ }
+ }
+ return arguments.ToString();
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/Properties/AssemblyInfo.cs b/csharp/src/ProtoGen/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..565894f2
--- /dev/null
+++ b/csharp/src/ProtoGen/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+
+[assembly: AssemblyTitle("ProtoGen")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ProtoGen")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("2.4.1.555")]
+
+[assembly: AssemblyVersion("2.4.1.555")]
+[assembly: AssemblyFileVersion("2.4.1.555")] \ No newline at end of file
diff --git a/csharp/src/ProtoGen/ProtoGen.csproj b/csharp/src/ProtoGen/ProtoGen.csproj
new file mode 100644
index 00000000..2de44aec
--- /dev/null
+++ b/csharp/src/ProtoGen/ProtoGen.csproj
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <EnvironmentFlavor>CLIENTPROFILE</EnvironmentFlavor>
+ <EnvironmentTemplate>NET35</EnvironmentTemplate>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{250ADE34-82FD-4BAE-86D5-985FBE589C4A}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Google.ProtocolBuffers.ProtoGen</RootNamespace>
+ <AssemblyName>ProtoGen</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\..\keys\Google.ProtocolBuffers.snk</AssemblyOriginatorKeyFile>
+ <StartupObject>Google.ProtocolBuffers.ProtoGen.ProgramPreprocess</StartupObject>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\NET35\Debug</OutputPath>
+ <IntermediateOutputPath>obj\NET35\Debug\</IntermediateOutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <NoStdLib>true</NoStdLib>
+ <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\NET35\Release</OutputPath>
+ <IntermediateOutputPath>obj\NET35\Release\</IntermediateOutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <NoStdLib>true</NoStdLib>
+ <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="DescriptorUtil.cs" />
+ <Compile Include="EnumFieldGenerator.cs" />
+ <Compile Include="EnumGenerator.cs" />
+ <Compile Include="ExtensionGenerator.cs" />
+ <Compile Include="FieldGeneratorBase.cs" />
+ <Compile Include="IFieldSourceGenerator.cs" />
+ <Compile Include="ISourceGenerator.cs" />
+ <Compile Include="MessageFieldGenerator.cs" />
+ <Compile Include="MessageGenerator.cs" />
+ <Compile Include="PluginProtoFile.cs" />
+ <Compile Include="PrimitiveFieldGenerator.cs" />
+ <Compile Include="ProgramPreprocess.cs" />
+ <Compile Include="RepeatedEnumFieldGenerator.cs" />
+ <Compile Include="RepeatedMessageFieldGenerator.cs" />
+ <Compile Include="RepeatedPrimitiveFieldGenerator.cs" />
+ <Compile Include="ServiceGenerator.cs" />
+ <Compile Include="DependencyResolutionException.cs" />
+ <Compile Include="Generator.cs" />
+ <Compile Include="GeneratorOptions.cs" />
+ <Compile Include="Helpers.cs" />
+ <Compile Include="InvalidOptionsException.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ServiceInterfaceGenerator.cs" />
+ <Compile Include="SourceGeneratorBase.cs" />
+ <Compile Include="SourceGenerators.cs" />
+ <Compile Include="UmbrellaClassGenerator.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\ProtocolBuffers\ProtocolBuffers.csproj">
+ <Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>
+ <Name>ProtocolBuffers</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/csharp/src/ProtoGen/ProtocGenCs.cs b/csharp/src/ProtoGen/ProtocGenCs.cs
new file mode 100644
index 00000000..29264200
--- /dev/null
+++ b/csharp/src/ProtoGen/ProtocGenCs.cs
@@ -0,0 +1,76 @@
+using Google.ProtocolBuffers.Compiler.PluginProto;
+using Google.ProtocolBuffers.DescriptorProtos;
+using System;
+using System.Collections.Generic;
+
+// Usage example:
+// protoc.exe
+// --plugin=path\to\protoc-gen-cs.exe
+// --cs_out="-generated_code_attributes=true umbrella_namespace=TutorialProto :."
+// --proto_path=.\protos\
+// protos\tutorial\addressbook.proto
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ public static class ProtocGenCs
+ {
+ internal static void Run(CodeGeneratorRequest request, CodeGeneratorResponse.Builder response)
+ {
+ var arguments = new List<string>();
+ foreach (var arg in request.Parameter.Split(' '))
+ {
+ var timmedArg = (arg ?? "").Trim();
+ if (!string.IsNullOrEmpty(timmedArg))
+ {
+ arguments.Add(timmedArg);
+ }
+ }
+ // Adding fake input file to make TryValidate happy.
+ arguments.Add(System.Reflection.Assembly.GetExecutingAssembly().Location);
+
+ GeneratorOptions options = new GeneratorOptions
+ {
+ Arguments = arguments
+ };
+ IList<string> validationFailures;
+ if (!options.TryValidate(out validationFailures))
+ {
+ response.Error += new InvalidOptionsException(validationFailures).Message;
+ return;
+ }
+
+ Generator generator = Generator.CreateGenerator(options);
+ generator.Generate(request, response);
+ }
+
+ public static int Main(string[] args)
+ {
+ // Hack to make sure everything's initialized
+ DescriptorProtoFile.Descriptor.ToString();
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
+ CSharpOptions.RegisterAllExtensions(extensionRegistry);
+
+ CodeGeneratorRequest request;
+ var response = new CodeGeneratorResponse.Builder();
+ try
+ {
+ using (var input = Console.OpenStandardInput())
+ {
+ request = CodeGeneratorRequest.ParseFrom(input, extensionRegistry);
+ }
+ Run(request, response);
+ }
+ catch (Exception e)
+ {
+ response.Error += e.ToString();
+ }
+
+ using (var output = Console.OpenStandardOutput())
+ {
+ response.Build().WriteTo(output);
+ output.Flush();
+ }
+ return 0;
+ }
+ }
+}
diff --git a/csharp/src/ProtoGen/RepeatedEnumFieldGenerator.cs b/csharp/src/ProtoGen/RepeatedEnumFieldGenerator.cs
new file mode 100644
index 00000000..8c9f17b8
--- /dev/null
+++ b/csharp/src/ProtoGen/RepeatedEnumFieldGenerator.cs
@@ -0,0 +1,212 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class RepeatedEnumFieldGenerator : FieldGeneratorBase, IFieldSourceGenerator
+ {
+ internal RepeatedEnumFieldGenerator(FieldDescriptor descriptor, int fieldOrdinal)
+ : base(descriptor, fieldOrdinal)
+ {
+ }
+
+ public void GenerateMembers(TextGenerator writer)
+ {
+ if (Descriptor.IsPacked && OptimizeSpeed)
+ {
+ writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
+ }
+ writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
+ writer.WriteLine("}");
+
+ // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option.
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public int {0}Count {{", PropertyName);
+ writer.WriteLine(" get {{ return {0}_.Count; }}", Name);
+ writer.WriteLine("}");
+
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
+ writer.WriteLine(" return {0}_[index];", Name);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuilderMembers(TextGenerator writer)
+ {
+ // Note: We can return the original list here, because we make it unmodifiable when we build
+ // We return it via IPopsicleList so that collection initializers work more pleasantly.
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return PrepareBuilder().{0}_; }}", Name);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public int {0}Count {{", PropertyName);
+ writer.WriteLine(" get {{ return result.{0}Count; }}", PropertyName);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
+ writer.WriteLine(" return result.Get{0}(index);", PropertyName);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_[index] = value;", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(value);", Name, TypeName);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(values);", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Clear();", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ }
+
+ public void GenerateMergingCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (other.{0}_.Count != 0) {{", Name);
+ writer.WriteLine(" result.{0}_.Add(other.{0}_);", Name);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuildingCode(TextGenerator writer)
+ {
+ writer.WriteLine("{0}_.MakeReadOnly();", Name);
+ }
+
+ public void GenerateParsingCode(TextGenerator writer)
+ {
+ writer.WriteLine("scg::ICollection<object> unknownItems;");
+ writer.WriteLine("input.ReadEnumArray<{0}>(tag, field_name, result.{1}_, out unknownItems);", TypeName, Name);
+ if (!UseLiteRuntime)
+ {
+ writer.WriteLine("if (unknownItems != null) {");
+ writer.WriteLine(" if (unknownFields == null) {");
+ writer.WriteLine(" unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);");
+ writer.WriteLine(" }");
+ writer.WriteLine(" foreach (object rawValue in unknownItems)");
+ writer.WriteLine(" if (rawValue is int)");
+ writer.WriteLine(" unknownFields.MergeVarintField({0}, (ulong)(int)rawValue);", Number);
+ writer.WriteLine("}");
+ }
+ }
+
+ public void GenerateSerializationCode(TextGenerator writer)
+ {
+ writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+ writer.Indent();
+ if (Descriptor.IsPacked)
+ {
+ writer.WriteLine(
+ "output.WritePackedEnumArray({0}, field_names[{2}], {1}MemoizedSerializedSize, {1}_);", Number, Name,
+ FieldOrdinal, Descriptor.FieldType);
+ }
+ else
+ {
+ writer.WriteLine("output.WriteEnumArray({0}, field_names[{2}], {1}_);", Number, Name, FieldOrdinal,
+ Descriptor.FieldType);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+
+ public void GenerateSerializedSizeCode(TextGenerator writer)
+ {
+ writer.WriteLine("{");
+ writer.Indent();
+ writer.WriteLine("int dataSize = 0;");
+ writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+ writer.Indent();
+ writer.WriteLine("foreach ({0} element in {1}_) {{", TypeName, Name);
+ writer.WriteLine(" dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);");
+ writer.WriteLine("}");
+ writer.WriteLine("size += dataSize;");
+ int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
+ if (Descriptor.IsPacked)
+ {
+ writer.WriteLine("size += {0};", tagSize);
+ writer.WriteLine("size += pb::CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);");
+ }
+ else
+ {
+ writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ // cache the data size for packed fields.
+ if (Descriptor.IsPacked)
+ {
+ writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+
+ public override void WriteHash(TextGenerator writer)
+ {
+ writer.WriteLine("foreach({0} i in {1}_)", TypeName, Name);
+ writer.WriteLine(" hash ^= i.GetHashCode();");
+ }
+
+ public override void WriteEquals(TextGenerator writer)
+ {
+ writer.WriteLine("if({0}_.Count != other.{0}_.Count) return false;", Name);
+ writer.WriteLine("for(int ix=0; ix < {0}_.Count; ix++)", Name);
+ writer.WriteLine(" if(!{0}_[ix].Equals(other.{0}_[ix])) return false;", Name);
+ }
+
+ public override void WriteToString(TextGenerator writer)
+ {
+ writer.WriteLine("PrintField(\"{0}\", {1}_, writer);", Descriptor.Name, Name);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/RepeatedMessageFieldGenerator.cs b/csharp/src/ProtoGen/RepeatedMessageFieldGenerator.cs
new file mode 100644
index 00000000..a9a0143c
--- /dev/null
+++ b/csharp/src/ProtoGen/RepeatedMessageFieldGenerator.cs
@@ -0,0 +1,184 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class RepeatedMessageFieldGenerator : FieldGeneratorBase, IFieldSourceGenerator
+ {
+ internal RepeatedMessageFieldGenerator(FieldDescriptor descriptor, int fieldOrdinal)
+ : base(descriptor, fieldOrdinal)
+ {
+ }
+
+ public void GenerateMembers(TextGenerator writer)
+ {
+ writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return {0}_; }}", Name);
+ writer.WriteLine("}");
+
+ // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option.
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public int {0}Count {{", PropertyName);
+ writer.WriteLine(" get {{ return {0}_.Count; }}", Name);
+ writer.WriteLine("}");
+
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
+ writer.WriteLine(" return {0}_[index];", Name);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuilderMembers(TextGenerator writer)
+ {
+ // Note: We can return the original list here, because we make it unmodifiable when we build
+ // We return it via IPopsicleList so that collection initializers work more pleasantly.
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return PrepareBuilder().{0}_; }}", Name);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public int {0}Count {{", PropertyName);
+ writer.WriteLine(" get {{ return result.{0}Count; }}", PropertyName);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
+ writer.WriteLine(" return result.Get{0}(index);", PropertyName);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
+ AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_[index] = value;", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ // Extra overload for builder (just on messages)
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Set{0}(int index, {1}.Builder builderForValue) {{", PropertyName, TypeName);
+ AddNullCheck(writer, "builderForValue");
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_[index] = builderForValue.Build();", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
+ AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(value);", Name, TypeName);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ // Extra overload for builder (just on messages)
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Add{0}({1}.Builder builderForValue) {{", PropertyName, TypeName);
+ AddNullCheck(writer, "builderForValue");
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(builderForValue.Build());", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(values);", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Clear();", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ }
+
+ public void GenerateMergingCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (other.{0}_.Count != 0) {{", Name);
+ writer.WriteLine(" result.{0}_.Add(other.{0}_);", Name);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuildingCode(TextGenerator writer)
+ {
+ writer.WriteLine("{0}_.MakeReadOnly();", Name);
+ }
+
+ public void GenerateParsingCode(TextGenerator writer)
+ {
+ writer.WriteLine(
+ "input.Read{0}Array(tag, field_name, result.{1}_, {2}.DefaultInstance, extensionRegistry);",
+ MessageOrGroup, Name, TypeName);
+ }
+
+ public void GenerateSerializationCode(TextGenerator writer)
+ {
+ writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+ writer.Indent();
+ writer.WriteLine("output.Write{0}Array({1}, field_names[{3}], {2}_);", MessageOrGroup, Number, Name,
+ FieldOrdinal, Descriptor.FieldType);
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+
+ public void GenerateSerializedSizeCode(TextGenerator writer)
+ {
+ writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
+ writer.WriteLine(" size += pb::CodedOutputStream.Compute{0}Size({1}, element);", MessageOrGroup, Number);
+ writer.WriteLine("}");
+ }
+
+ public override void WriteHash(TextGenerator writer)
+ {
+ writer.WriteLine("foreach({0} i in {1}_)", TypeName, Name);
+ writer.WriteLine(" hash ^= i.GetHashCode();");
+ }
+
+ public override void WriteEquals(TextGenerator writer)
+ {
+ writer.WriteLine("if({0}_.Count != other.{0}_.Count) return false;", Name);
+ writer.WriteLine("for(int ix=0; ix < {0}_.Count; ix++)", Name);
+ writer.WriteLine(" if(!{0}_[ix].Equals(other.{0}_[ix])) return false;", Name);
+ }
+
+ public override void WriteToString(TextGenerator writer)
+ {
+ writer.WriteLine("PrintField(\"{0}\", {1}_, writer);",
+ Descriptor.FieldType == FieldType.Group ? Descriptor.MessageType.Name : Descriptor.Name,
+ Name);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs b/csharp/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
new file mode 100644
index 00000000..b795f3b6
--- /dev/null
+++ b/csharp/src/ProtoGen/RepeatedPrimitiveFieldGenerator.cs
@@ -0,0 +1,207 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class RepeatedPrimitiveFieldGenerator : FieldGeneratorBase, IFieldSourceGenerator
+ {
+ internal RepeatedPrimitiveFieldGenerator(FieldDescriptor descriptor, int fieldOrdinal)
+ : base(descriptor, fieldOrdinal)
+ {
+ }
+
+ public void GenerateMembers(TextGenerator writer)
+ {
+ if (Descriptor.IsPacked && OptimizeSpeed)
+ {
+ writer.WriteLine("private int {0}MemoizedSerializedSize;", Name);
+ }
+ writer.WriteLine("private pbc::PopsicleList<{0}> {1}_ = new pbc::PopsicleList<{0}>();", TypeName, Name);
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public scg::IList<{0}> {1}List {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return pbc::Lists.AsReadOnly({0}_); }}", Name);
+ writer.WriteLine("}");
+
+ // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option.
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public int {0}Count {{", PropertyName);
+ writer.WriteLine(" get {{ return {0}_.Count; }}", Name);
+ writer.WriteLine("}");
+
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
+ writer.WriteLine(" return {0}_[index];", Name);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuilderMembers(TextGenerator writer)
+ {
+ // Note: We can return the original list here, because we make it unmodifiable when we build
+ // We return it via IPopsicleList so that collection initializers work more pleasantly.
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public pbc::IPopsicleList<{0}> {1}List {{", TypeName, PropertyName);
+ writer.WriteLine(" get {{ return PrepareBuilder().{0}_; }}", Name);
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public int {0}Count {{", PropertyName);
+ writer.WriteLine(" get {{ return result.{0}Count; }}", PropertyName);
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public {0} Get{1}(int index) {{", TypeName, PropertyName);
+ writer.WriteLine(" return result.Get{0}(index);", PropertyName);
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public Builder Set{0}(int index, {1} value) {{", PropertyName, TypeName);
+ AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_[index] = value;", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public Builder Add{0}({1} value) {{", PropertyName, TypeName);
+ AddNullCheck(writer);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(value);", Name, TypeName);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddPublicMemberAttributes(writer);
+ writer.WriteLine("public Builder AddRange{0}(scg::IEnumerable<{1}> values) {{", PropertyName, TypeName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Add(values);", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ AddDeprecatedFlag(writer);
+ writer.WriteLine("public Builder Clear{0}() {{", PropertyName);
+ writer.WriteLine(" PrepareBuilder();");
+ writer.WriteLine(" result.{0}_.Clear();", Name);
+ writer.WriteLine(" return this;");
+ writer.WriteLine("}");
+ }
+
+ public void GenerateMergingCode(TextGenerator writer)
+ {
+ writer.WriteLine("if (other.{0}_.Count != 0) {{", Name);
+ writer.WriteLine(" result.{0}_.Add(other.{0}_);", Name);
+ writer.WriteLine("}");
+ }
+
+ public void GenerateBuildingCode(TextGenerator writer)
+ {
+ writer.WriteLine("{0}_.MakeReadOnly();", Name);
+ }
+
+ public void GenerateParsingCode(TextGenerator writer)
+ {
+ writer.WriteLine("input.Read{0}Array(tag, field_name, result.{1}_);", CapitalizedTypeName, Name,
+ Descriptor.FieldType);
+ }
+
+ public void GenerateSerializationCode(TextGenerator writer)
+ {
+ writer.WriteLine("if ({0}_.Count > 0) {{", Name);
+ writer.Indent();
+ if (Descriptor.IsPacked)
+ {
+ writer.WriteLine("output.WritePacked{0}Array({1}, field_names[{3}], {2}MemoizedSerializedSize, {2}_);",
+ CapitalizedTypeName, Number, Name, FieldOrdinal, Descriptor.FieldType);
+ }
+ else
+ {
+ writer.WriteLine("output.Write{0}Array({1}, field_names[{3}], {2}_);", CapitalizedTypeName, Number, Name,
+ FieldOrdinal, Descriptor.FieldType);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+
+ public void GenerateSerializedSizeCode(TextGenerator writer)
+ {
+ writer.WriteLine("{");
+ writer.Indent();
+ writer.WriteLine("int dataSize = 0;");
+ if (FixedSize == -1)
+ {
+ writer.WriteLine("foreach ({0} element in {1}List) {{", TypeName, PropertyName);
+ writer.WriteLine(" dataSize += pb::CodedOutputStream.Compute{0}SizeNoTag(element);",
+ CapitalizedTypeName, Number);
+ writer.WriteLine("}");
+ }
+ else
+ {
+ writer.WriteLine("dataSize = {0} * {1}_.Count;", FixedSize, Name);
+ }
+ writer.WriteLine("size += dataSize;");
+ int tagSize = CodedOutputStream.ComputeTagSize(Descriptor.FieldNumber);
+ if (Descriptor.IsPacked)
+ {
+ writer.WriteLine("if ({0}_.Count != 0) {{", Name);
+ writer.WriteLine(" size += {0} + pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);", tagSize);
+ writer.WriteLine("}");
+ }
+ else
+ {
+ writer.WriteLine("size += {0} * {1}_.Count;", tagSize, Name);
+ }
+ // cache the data size for packed fields.
+ if (Descriptor.IsPacked)
+ {
+ writer.WriteLine("{0}MemoizedSerializedSize = dataSize;", Name);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+
+ public override void WriteHash(TextGenerator writer)
+ {
+ writer.WriteLine("foreach({0} i in {1}_)", TypeName, Name);
+ writer.WriteLine(" hash ^= i.GetHashCode();");
+ }
+
+ public override void WriteEquals(TextGenerator writer)
+ {
+ writer.WriteLine("if({0}_.Count != other.{0}_.Count) return false;", Name);
+ writer.WriteLine("for(int ix=0; ix < {0}_.Count; ix++)", Name);
+ writer.WriteLine(" if(!{0}_[ix].Equals(other.{0}_[ix])) return false;", Name);
+ }
+
+ public override void WriteToString(TextGenerator writer)
+ {
+ writer.WriteLine("PrintField(\"{0}\", {1}_, writer);", Descriptor.Name, Name);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/ServiceGenerator.cs b/csharp/src/ProtoGen/ServiceGenerator.cs
new file mode 100644
index 00000000..a6b9eb28
--- /dev/null
+++ b/csharp/src/ProtoGen/ServiceGenerator.cs
@@ -0,0 +1,190 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class GenericServiceGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator
+ {
+ private enum RequestOrResponse
+ {
+ Request,
+ Response
+ }
+
+ internal GenericServiceGenerator(ServiceDescriptor descriptor)
+ : base(descriptor)
+ {
+ }
+
+ public void Generate(TextGenerator writer)
+ {
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("{0} abstract class {1} : pb::IService {{", ClassAccessLevel, Descriptor.Name);
+ writer.Indent();
+
+ foreach (MethodDescriptor method in Descriptor.Methods)
+ {
+ writer.WriteLine("{0} abstract void {1}(", ClassAccessLevel,
+ NameHelpers.UnderscoresToPascalCase(method.Name));
+ writer.WriteLine(" pb::IRpcController controller,");
+ writer.WriteLine(" {0} request,", GetClassName(method.InputType));
+ writer.WriteLine(" global::System.Action<{0}> done);", GetClassName(method.OutputType));
+ }
+
+ // Generate Descriptor and DescriptorForType.
+ writer.WriteLine();
+ writer.WriteLine("{0} static pbd::ServiceDescriptor Descriptor {{", ClassAccessLevel);
+ writer.WriteLine(" get {{ return {0}.Descriptor.Services[{1}]; }}",
+ DescriptorUtil.GetQualifiedUmbrellaClassName(Descriptor.File.CSharpOptions),
+ Descriptor.Index);
+ writer.WriteLine("}");
+ writer.WriteLine("public pbd::ServiceDescriptor DescriptorForType {");
+ writer.WriteLine(" get { return Descriptor; }");
+ writer.WriteLine("}");
+
+ GenerateCallMethod(writer);
+ GenerateGetPrototype(RequestOrResponse.Request, writer);
+ GenerateGetPrototype(RequestOrResponse.Response, writer);
+ GenerateStub(writer);
+
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+
+ private void GenerateCallMethod(TextGenerator writer)
+ {
+ writer.WriteLine();
+ writer.WriteLine("public void CallMethod(");
+ writer.WriteLine(" pbd::MethodDescriptor method,");
+ writer.WriteLine(" pb::IRpcController controller,");
+ writer.WriteLine(" pb::IMessage request,");
+ writer.WriteLine(" global::System.Action<pb::IMessage> done) {");
+ writer.Indent();
+ writer.WriteLine("if (method.Service != Descriptor) {");
+ writer.WriteLine(" throw new global::System.ArgumentException(");
+ writer.WriteLine(" \"Service.CallMethod() given method descriptor for wrong service type.\");");
+ writer.WriteLine("}");
+ writer.WriteLine("switch(method.Index) {");
+ writer.Indent();
+ foreach (MethodDescriptor method in Descriptor.Methods)
+ {
+ writer.WriteLine("case {0}:", method.Index);
+ writer.WriteLine(" this.{0}(controller, ({1}) request,",
+ NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType));
+ writer.WriteLine(" pb::RpcUtil.SpecializeCallback<{0}>(", GetClassName(method.OutputType));
+ writer.WriteLine(" done));");
+ writer.WriteLine(" return;");
+ }
+ writer.WriteLine("default:");
+ writer.WriteLine(" throw new global::System.InvalidOperationException(\"Can't get here.\");");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+
+ private void GenerateGetPrototype(RequestOrResponse which, TextGenerator writer)
+ {
+ writer.WriteLine("public pb::IMessage Get{0}Prototype(pbd::MethodDescriptor method) {{", which);
+ writer.Indent();
+ writer.WriteLine("if (method.Service != Descriptor) {");
+ writer.WriteLine(" throw new global::System.ArgumentException(");
+ writer.WriteLine(" \"Service.Get{0}Prototype() given method descriptor for wrong service type.\");",
+ which);
+ writer.WriteLine("}");
+ writer.WriteLine("switch(method.Index) {");
+ writer.Indent();
+
+ foreach (MethodDescriptor method in Descriptor.Methods)
+ {
+ writer.WriteLine("case {0}:", method.Index);
+ writer.WriteLine(" return {0}.DefaultInstance;",
+ GetClassName(which == RequestOrResponse.Request ? method.InputType : method.OutputType));
+ }
+ writer.WriteLine("default:");
+ writer.WriteLine(" throw new global::System.InvalidOperationException(\"Can't get here.\");");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+
+ private void GenerateStub(TextGenerator writer)
+ {
+ writer.WriteLine("public static Stub CreateStub(pb::IRpcChannel channel) {");
+ writer.WriteLine(" return new Stub(channel);");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("{0} class Stub : {1} {{", ClassAccessLevel, GetClassName(Descriptor));
+ writer.Indent();
+ writer.WriteLine("internal Stub(pb::IRpcChannel channel) {");
+ writer.WriteLine(" this.channel = channel;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine("private readonly pb::IRpcChannel channel;");
+ writer.WriteLine();
+ writer.WriteLine("public pb::IRpcChannel Channel {");
+ writer.WriteLine(" get { return channel; }");
+ writer.WriteLine("}");
+
+ foreach (MethodDescriptor method in Descriptor.Methods)
+ {
+ writer.WriteLine();
+ writer.WriteLine("{0} override void {1}(", ClassAccessLevel,
+ NameHelpers.UnderscoresToPascalCase(method.Name));
+ writer.WriteLine(" pb::IRpcController controller,");
+ writer.WriteLine(" {0} request,", GetClassName(method.InputType));
+ writer.WriteLine(" global::System.Action<{0}> done) {{", GetClassName(method.OutputType));
+ writer.Indent();
+ writer.WriteLine("channel.CallMethod(Descriptor.Methods[{0}],", method.Index);
+ writer.WriteLine(" controller, request, {0}.DefaultInstance,", GetClassName(method.OutputType));
+ writer.WriteLine(" pb::RpcUtil.GeneralizeCallback<{0}, {0}.Builder>(done, {0}.DefaultInstance));",
+ GetClassName(method.OutputType));
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/ServiceInterfaceGenerator.cs b/csharp/src/ProtoGen/ServiceInterfaceGenerator.cs
new file mode 100644
index 00000000..11e3d3d0
--- /dev/null
+++ b/csharp/src/ProtoGen/ServiceInterfaceGenerator.cs
@@ -0,0 +1,300 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal class ServiceGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator
+ {
+ private readonly CSharpServiceType svcType;
+ private ISourceGenerator _generator;
+
+ internal ServiceGenerator(ServiceDescriptor descriptor)
+ : base(descriptor)
+ {
+ svcType = descriptor.File.CSharpOptions.ServiceGeneratorType;
+ switch (svcType)
+ {
+ case CSharpServiceType.NONE:
+ _generator = new NoServicesGenerator(descriptor);
+ break;
+ case CSharpServiceType.GENERIC:
+ _generator = new GenericServiceGenerator(descriptor);
+ break;
+ case CSharpServiceType.INTERFACE:
+ _generator = new ServiceInterfaceGenerator(descriptor);
+ break;
+ case CSharpServiceType.IRPCDISPATCH:
+ _generator = new RpcServiceGenerator(descriptor);
+ break;
+ default:
+ throw new ApplicationException("Unknown ServiceGeneratorType = " + svcType.ToString());
+ }
+ }
+
+ public void Generate(TextGenerator writer)
+ {
+ _generator.Generate(writer);
+ }
+
+ private class NoServicesGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator
+ {
+ public NoServicesGenerator(ServiceDescriptor descriptor)
+ : base(descriptor)
+ {
+ }
+
+ public virtual void Generate(TextGenerator writer)
+ {
+ writer.WriteLine("/*");
+ writer.WriteLine("* Service generation is now disabled by default, use the following option to enable:");
+ writer.WriteLine("* option (google.protobuf.csharp_file_options).service_generator_type = GENERIC;");
+ writer.WriteLine("*/");
+ }
+ }
+
+ private class ServiceInterfaceGenerator : SourceGeneratorBase<ServiceDescriptor>, ISourceGenerator
+ {
+ public ServiceInterfaceGenerator(ServiceDescriptor descriptor)
+ : base(descriptor)
+ {
+ }
+
+ public virtual void Generate(TextGenerator writer)
+ {
+ CSharpServiceOptions options = Descriptor.Options.GetExtension(CSharpOptions.CsharpServiceOptions);
+ if (options != null && options.HasInterfaceId)
+ {
+ writer.WriteLine("[global::System.Runtime.InteropServices.GuidAttribute(\"{0}\")]",
+ new Guid(options.InterfaceId));
+ }
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("{0} partial interface I{1} {{", ClassAccessLevel, Descriptor.Name);
+ writer.Indent();
+
+ foreach (MethodDescriptor method in Descriptor.Methods)
+ {
+ CSharpMethodOptions mth = method.Options.GetExtension(CSharpOptions.CsharpMethodOptions);
+ if (mth.HasDispatchId)
+ {
+ writer.WriteLine("[global::System.Runtime.InteropServices.DispId({0})]", mth.DispatchId);
+ }
+ writer.WriteLine("{0} {1}({2} {3});", GetClassName(method.OutputType),
+ NameHelpers.UnderscoresToPascalCase(method.Name), GetClassName(method.InputType),
+ NameHelpers.UnderscoresToCamelCase(method.InputType.Name));
+ }
+
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+ }
+
+ private class RpcServiceGenerator : ServiceInterfaceGenerator
+ {
+ public RpcServiceGenerator(ServiceDescriptor descriptor)
+ : base(descriptor)
+ {
+ }
+
+ public override void Generate(TextGenerator writer)
+ {
+ base.Generate(writer);
+
+ writer.WriteLine();
+
+ // CLIENT Proxy
+ {
+ if (Descriptor.File.CSharpOptions.ClsCompliance)
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("{0} partial class {1} : I{1}, pb::IRpcDispatch, global::System.IDisposable {{",
+ ClassAccessLevel, Descriptor.Name);
+ writer.Indent();
+ writer.WriteLine("private readonly bool dispose;");
+ writer.WriteLine("private readonly pb::IRpcDispatch dispatch;");
+
+ writer.WriteLine("public {0}(pb::IRpcDispatch dispatch) : this(dispatch, true) {{", Descriptor.Name);
+ writer.WriteLine("}");
+ writer.WriteLine("public {0}(pb::IRpcDispatch dispatch, bool dispose) {{", Descriptor.Name);
+ writer.WriteLine(" pb::ThrowHelper.ThrowIfNull(this.dispatch = dispatch, \"dispatch\");");
+ writer.WriteLine(" this.dispose = dispose && dispatch is global::System.IDisposable;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine("public void Dispose() {");
+ writer.WriteLine(" if (dispose) ((global::System.IDisposable)dispatch).Dispose();");
+ writer.WriteLine("}");
+ writer.WriteLine();
+ writer.WriteLine(
+ "TMessage pb::IRpcDispatch.CallMethod<TMessage, TBuilder>(string method, pb::IMessageLite request, pb::IBuilderLite<TMessage, TBuilder> response) {");
+ writer.WriteLine(" return dispatch.CallMethod(method, request, response);");
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ foreach (MethodDescriptor method in Descriptor.Methods)
+ {
+ writer.WriteLine("public {0} {1}({2} {3}) {{", GetClassName(method.OutputType),
+ NameHelpers.UnderscoresToPascalCase(method.Name),
+ GetClassName(method.InputType),
+ NameHelpers.UnderscoresToCamelCase(method.InputType.Name));
+ writer.WriteLine(" return dispatch.CallMethod(\"{0}\", {1}, {2}.CreateBuilder());",
+ method.Name,
+ NameHelpers.UnderscoresToCamelCase(method.InputType.Name),
+ GetClassName(method.OutputType)
+ );
+ writer.WriteLine("}");
+ writer.WriteLine();
+ }
+ }
+ // SERVER - DISPATCH
+ {
+ if (Descriptor.File.CSharpOptions.ClsCompliance)
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("public partial class Dispatch : pb::IRpcDispatch, global::System.IDisposable {");
+ writer.Indent();
+ writer.WriteLine("private readonly bool dispose;");
+ writer.WriteLine("private readonly I{0} implementation;", Descriptor.Name);
+
+ writer.WriteLine("public Dispatch(I{0} implementation) : this(implementation, true) {{",
+ Descriptor.Name);
+ writer.WriteLine("}");
+ writer.WriteLine("public Dispatch(I{0} implementation, bool dispose) {{", Descriptor.Name);
+ writer.WriteLine(" pb::ThrowHelper.ThrowIfNull(this.implementation = implementation, \"implementation\");");
+ writer.WriteLine(" this.dispose = dispose && implementation is global::System.IDisposable;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine("public void Dispose() {");
+ writer.WriteLine(" if (dispose) ((global::System.IDisposable)implementation).Dispose();");
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine(
+ "public TMessage CallMethod<TMessage, TBuilder>(string methodName, pb::IMessageLite request, pb::IBuilderLite<TMessage, TBuilder> response)");
+ writer.WriteLine(" where TMessage : pb::IMessageLite<TMessage, TBuilder>");
+ writer.WriteLine(" where TBuilder : pb::IBuilderLite<TMessage, TBuilder> {");
+ writer.Indent();
+ writer.WriteLine("switch(methodName) {");
+ writer.Indent();
+
+ foreach (MethodDescriptor method in Descriptor.Methods)
+ {
+ writer.WriteLine(
+ "case \"{0}\": return response.MergeFrom(implementation.{1}(({2})request)).Build();",
+ method.Name, NameHelpers.UnderscoresToPascalCase(method.Name),
+ GetClassName(method.InputType));
+ }
+ writer.WriteLine("default: throw pb::ThrowHelper.CreateMissingMethod(typeof(I{0}), methodName);", Descriptor.Name);
+ writer.Outdent();
+ writer.WriteLine("}"); //end switch
+ writer.Outdent();
+ writer.WriteLine("}"); //end invoke
+ writer.Outdent();
+ writer.WriteLine("}"); //end server
+ }
+ // SERVER - STUB
+ {
+ if (Descriptor.File.CSharpOptions.ClsCompliance)
+ {
+ writer.WriteLine("[global::System.CLSCompliant(false)]");
+ }
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine(
+ "public partial class ServerStub : pb::IRpcServerStub, global::System.IDisposable {");
+ writer.Indent();
+ writer.WriteLine("private readonly bool dispose;");
+ writer.WriteLine("private readonly pb::IRpcDispatch implementation;", Descriptor.Name);
+
+ writer.WriteLine("public ServerStub(I{0} implementation) : this(implementation, true) {{",
+ Descriptor.Name);
+ writer.WriteLine("}");
+ writer.WriteLine(
+ "public ServerStub(I{0} implementation, bool dispose) : this(new Dispatch(implementation, dispose), dispose) {{",
+ Descriptor.Name);
+ writer.WriteLine("}");
+
+ writer.WriteLine("public ServerStub(pb::IRpcDispatch implementation) : this(implementation, true) {");
+ writer.WriteLine("}");
+ writer.WriteLine("public ServerStub(pb::IRpcDispatch implementation, bool dispose) {");
+ writer.WriteLine(" pb::ThrowHelper.ThrowIfNull(this.implementation = implementation, \"implementation\");");
+ writer.WriteLine(" this.dispose = dispose && implementation is global::System.IDisposable;");
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine("public void Dispose() {");
+ writer.WriteLine(" if (dispose) ((global::System.IDisposable)implementation).Dispose();");
+ writer.WriteLine("}");
+ writer.WriteLine();
+
+ writer.WriteLine(
+ "public pb::IMessageLite CallMethod(string methodName, pb::ICodedInputStream input, pb::ExtensionRegistry registry) {{",
+ Descriptor.Name);
+ writer.Indent();
+ writer.WriteLine("switch(methodName) {");
+ writer.Indent();
+
+ foreach (MethodDescriptor method in Descriptor.Methods)
+ {
+ writer.WriteLine(
+ "case \"{0}\": return implementation.CallMethod(methodName, {1}.ParseFrom(input, registry), {2}.CreateBuilder());",
+ method.Name, GetClassName(method.InputType), GetClassName(method.OutputType));
+ }
+ writer.WriteLine("default: throw pb::ThrowHelper.CreateMissingMethod(typeof(I{0}), methodName);", Descriptor.Name);
+ writer.Outdent();
+ writer.WriteLine("}"); //end switch
+ writer.Outdent();
+ writer.WriteLine("}"); //end invoke
+ writer.Outdent();
+ writer.WriteLine("}"); //end server
+ }
+
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/SourceGeneratorBase.cs b/csharp/src/ProtoGen/SourceGeneratorBase.cs
new file mode 100644
index 00000000..535c6f73
--- /dev/null
+++ b/csharp/src/ProtoGen/SourceGeneratorBase.cs
@@ -0,0 +1,167 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System.Collections.Generic;
+using Google.ProtocolBuffers.DescriptorProtos;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ internal abstract class SourceGeneratorBase<T> where T : IDescriptor
+ {
+ private readonly T descriptor;
+
+ protected readonly bool OptimizeSpeed;
+ protected readonly bool OptimizeSize;
+ protected readonly bool UseLiteRuntime;
+ protected readonly string RuntimeSuffix;
+
+ protected SourceGeneratorBase(T descriptor)
+ {
+ this.descriptor = descriptor;
+
+ OptimizeSize = descriptor.File.Options.OptimizeFor ==
+ FileOptions.Types.OptimizeMode.CODE_SIZE;
+ OptimizeSpeed = descriptor.File.Options.OptimizeFor ==
+ FileOptions.Types.OptimizeMode.SPEED;
+ UseLiteRuntime = descriptor.File.Options.OptimizeFor ==
+ FileOptions.Types.OptimizeMode.LITE_RUNTIME;
+ //Lite runtime uses OptimizeSpeed code branches
+ OptimizeSpeed |= UseLiteRuntime;
+ RuntimeSuffix = UseLiteRuntime ? "Lite" : "";
+ }
+
+ protected T Descriptor
+ {
+ get { return descriptor; }
+ }
+
+ internal static string GetClassName(IDescriptor descriptor)
+ {
+ return ToCSharpName(descriptor.FullName, descriptor.File);
+ }
+
+ // Groups are hacky: The name of the field is just the lower-cased name
+ // of the group type. In C#, though, we would like to retain the original
+ // capitalization of the type name.
+ internal static string GetFieldName(FieldDescriptor descriptor)
+ {
+ if (descriptor.FieldType == FieldType.Group)
+ {
+ return descriptor.MessageType.Name;
+ }
+ else
+ {
+ return descriptor.Name;
+ }
+ }
+
+ internal static string GetFieldConstantName(FieldDescriptor field)
+ {
+ return field.CSharpOptions.PropertyName + "FieldNumber";
+ }
+
+ private static string ToCSharpName(string name, FileDescriptor file)
+ {
+ string result = file.CSharpOptions.Namespace;
+ if (file.CSharpOptions.NestClasses)
+ {
+ if (result != "")
+ {
+ result += ".";
+ }
+ result += file.CSharpOptions.UmbrellaClassname;
+ }
+ if (result != "")
+ {
+ result += '.';
+ }
+ string classname;
+ if (file.Package == "")
+ {
+ classname = name;
+ }
+ else
+ {
+ // Strip the proto package from full_name since we've replaced it with
+ // the C# namespace.
+ classname = name.Substring(file.Package.Length + 1);
+ }
+ result += classname.Replace(".", ".Types.");
+ return "global::" + result;
+ }
+
+ protected string ClassAccessLevel
+ {
+ get { return descriptor.File.CSharpOptions.PublicClasses ? "public" : "internal"; }
+ }
+
+ protected void WriteGeneratedCodeAttributes(TextGenerator writer)
+ {
+ if (descriptor.File.CSharpOptions.GeneratedCodeAttributes)
+ {
+ writer.WriteLine("[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]");
+ writer.WriteLine("[global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"{0}\", \"{1}\")]",
+ GetType().Assembly.GetName().Name, GetType().Assembly.GetName().Version);
+ }
+ }
+
+ protected void WriteChildren<TChild>(TextGenerator writer, string region, IEnumerable<TChild> children)
+ where TChild : IDescriptor
+ {
+ // Copy the set of children; makes access easier
+ List<TChild> copy = new List<TChild>(children);
+ if (copy.Count == 0)
+ {
+ return;
+ }
+
+ if (region != null)
+ {
+ writer.WriteLine("#region {0}", region);
+ }
+ foreach (TChild child in children)
+ {
+ SourceGenerators.CreateGenerator(child).Generate(writer);
+ }
+ if (region != null)
+ {
+ writer.WriteLine("#endregion");
+ writer.WriteLine();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/SourceGenerators.cs b/csharp/src/ProtoGen/SourceGenerators.cs
new file mode 100644
index 00000000..38458f05
--- /dev/null
+++ b/csharp/src/ProtoGen/SourceGenerators.cs
@@ -0,0 +1,87 @@
+#region Copyright notice and license
+
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ public delegate TResult Func<T, TResult>(T arg);
+
+ internal static class SourceGenerators
+ {
+ private static readonly Dictionary<Type, Func<IDescriptor, ISourceGenerator>> GeneratorFactories =
+ new Dictionary<Type, Func<IDescriptor, ISourceGenerator>>
+ {
+ {typeof(FileDescriptor), descriptor => new UmbrellaClassGenerator((FileDescriptor) descriptor)},
+ {typeof(EnumDescriptor), descriptor => new EnumGenerator((EnumDescriptor) descriptor)},
+ {typeof(ServiceDescriptor), descriptor => new ServiceGenerator((ServiceDescriptor) descriptor)},
+ {typeof(MessageDescriptor), descriptor => new MessageGenerator((MessageDescriptor) descriptor)},
+ // For other fields, we have IFieldSourceGenerators.
+ {typeof(FieldDescriptor), descriptor => new ExtensionGenerator((FieldDescriptor) descriptor)}
+ };
+
+ public static IFieldSourceGenerator CreateFieldGenerator(FieldDescriptor field, int fieldOrdinal)
+ {
+ switch (field.MappedType)
+ {
+ case MappedType.Message:
+ return field.IsRepeated
+ ? (IFieldSourceGenerator) new RepeatedMessageFieldGenerator(field, fieldOrdinal)
+ : new MessageFieldGenerator(field, fieldOrdinal);
+ case MappedType.Enum:
+ return field.IsRepeated
+ ? (IFieldSourceGenerator) new RepeatedEnumFieldGenerator(field, fieldOrdinal)
+ : new EnumFieldGenerator(field, fieldOrdinal);
+ default:
+ return field.IsRepeated
+ ? (IFieldSourceGenerator) new RepeatedPrimitiveFieldGenerator(field, fieldOrdinal)
+ : new PrimitiveFieldGenerator(field, fieldOrdinal);
+ }
+ }
+
+ public static ISourceGenerator CreateGenerator<T>(T descriptor) where T : IDescriptor
+ {
+ Func<IDescriptor, ISourceGenerator> factory;
+ if (!GeneratorFactories.TryGetValue(typeof(T), out factory))
+ {
+ throw new ArgumentException("No generator registered for " + typeof(T).Name);
+ }
+ return factory(descriptor);
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/UmbrellaClassGenerator.cs b/csharp/src/ProtoGen/UmbrellaClassGenerator.cs
new file mode 100644
index 00000000..d83b2dbd
--- /dev/null
+++ b/csharp/src/ProtoGen/UmbrellaClassGenerator.cs
@@ -0,0 +1,294 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://github.com/jskeet/dotnet-protobufs/
+// Original C++/Java/Python code:
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Google.ProtocolBuffers.Descriptors;
+
+namespace Google.ProtocolBuffers.ProtoGen
+{
+ /// <summary>
+ /// Generator for the class describing the .proto file in general,
+ /// containing things like the message descriptor.
+ /// </summary>
+ internal sealed class UmbrellaClassGenerator : SourceGeneratorBase<FileDescriptor>, ISourceGenerator
+ {
+ internal UmbrellaClassGenerator(FileDescriptor descriptor)
+ : base(descriptor)
+ {
+ }
+
+ // Recursively searches the given message to see if it contains any extensions.
+ private static bool UsesExtensions(IMessage message)
+ {
+ // We conservatively assume that unknown fields are extensions.
+ if (message.UnknownFields.FieldDictionary.Count > 0)
+ {
+ return true;
+ }
+
+ foreach (KeyValuePair<FieldDescriptor, object> keyValue in message.AllFields)
+ {
+ FieldDescriptor field = keyValue.Key;
+ if (field.IsExtension)
+ {
+ return true;
+ }
+ if (field.MappedType == MappedType.Message)
+ {
+ if (field.IsRepeated)
+ {
+ foreach (IMessage subMessage in (IEnumerable) keyValue.Value)
+ {
+ if (UsesExtensions(subMessage))
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ if (UsesExtensions((IMessage) keyValue.Value))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public void Generate(TextGenerator writer)
+ {
+ WriteIntroduction(writer);
+ WriteExtensionRegistration(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");
+ if (!UseLiteRuntime)
+ {
+ WriteDescriptor(writer);
+ }
+ else
+ {
+ WriteLiteExtensions(writer);
+ }
+ // The class declaration either gets closed before or after the children are written.
+ if (!Descriptor.CSharpOptions.NestClasses)
+ {
+ writer.Outdent();
+ writer.WriteLine("}");
+
+ // Close the namespace around the umbrella class if defined
+ if (!Descriptor.CSharpOptions.NestClasses && Descriptor.CSharpOptions.UmbrellaNamespace != "")
+ {
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+ }
+ WriteChildren(writer, "Enums", Descriptor.EnumTypes);
+ WriteChildren(writer, "Messages", Descriptor.MessageTypes);
+ WriteChildren(writer, "Services", Descriptor.Services);
+ if (Descriptor.CSharpOptions.NestClasses)
+ {
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+ if (Descriptor.CSharpOptions.Namespace != "")
+ {
+ writer.Outdent();
+ writer.WriteLine("}");
+ }
+ writer.WriteLine();
+ writer.WriteLine("#endregion Designer generated code");
+ }
+
+ private void WriteIntroduction(TextGenerator writer)
+ {
+ writer.WriteLine("// Generated by {0}. DO NOT EDIT!", this.GetType().Assembly.FullName);
+ writer.WriteLine("#pragma warning disable 1591, 0612, 3021");
+ writer.WriteLine("#region Designer generated code");
+
+ writer.WriteLine();
+ writer.WriteLine("using pb = global::Google.ProtocolBuffers;");
+ writer.WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;");
+ writer.WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;");
+ writer.WriteLine("using scg = global::System.Collections.Generic;");
+
+ if (Descriptor.CSharpOptions.Namespace != "")
+ {
+ writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.Namespace);
+ writer.Indent();
+ writer.WriteLine();
+ }
+ // Add the namespace around the umbrella class if defined
+ if (!Descriptor.CSharpOptions.NestClasses && Descriptor.CSharpOptions.UmbrellaNamespace != "")
+ {
+ writer.WriteLine("namespace {0} {{", Descriptor.CSharpOptions.UmbrellaNamespace);
+ writer.Indent();
+ writer.WriteLine();
+ }
+
+ if (Descriptor.CSharpOptions.CodeContracts)
+ {
+ writer.WriteLine("[global::System.Diagnostics.Contracts.ContractVerificationAttribute(false)]");
+ }
+ writer.WriteLine("[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer.WriteLine("{0} static partial class {1} {{", ClassAccessLevel,
+ Descriptor.CSharpOptions.UmbrellaClassname);
+ writer.WriteLine();
+ writer.Indent();
+ }
+
+ private void WriteExtensionRegistration(TextGenerator writer)
+ {
+ writer.WriteLine("#region Extension registration");
+ writer.WriteLine("public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {");
+ writer.Indent();
+ foreach (FieldDescriptor extension in Descriptor.Extensions)
+ {
+ new ExtensionGenerator(extension).GenerateExtensionRegistrationCode(writer);
+ }
+ foreach (MessageDescriptor message in Descriptor.MessageTypes)
+ {
+ new MessageGenerator(message).GenerateExtensionRegistrationCode(writer);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine("#endregion");
+ }
+
+ 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 pbd::FileDescriptor descriptor;");
+ writer.WriteLine();
+ writer.WriteLine("static {0}() {{", Descriptor.CSharpOptions.UmbrellaClassname);
+ writer.Indent();
+ writer.WriteLine("byte[] descriptorData = global::System.Convert.FromBase64String(");
+ writer.Indent();
+ writer.Indent();
+ writer.WriteLine("string.Concat(");
+ 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.Outdent();
+ writer.WriteLine("\"{0}\"));", base64);
+ writer.Outdent();
+ writer.Outdent();
+ writer.WriteLine(
+ "pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {");
+ writer.Indent();
+ writer.WriteLine("descriptor = root;");
+ foreach (MessageDescriptor message in Descriptor.MessageTypes)
+ {
+ new MessageGenerator(message).GenerateStaticVariableInitializers(writer);
+ }
+ foreach (FieldDescriptor extension in Descriptor.Extensions)
+ {
+ new ExtensionGenerator(extension).GenerateStaticVariableInitializers(writer);
+ }
+
+ if (UsesExtensions(Descriptor.Proto))
+ {
+ // Must construct an ExtensionRegistry containing all possible extensions
+ // and return it.
+ writer.WriteLine("pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();");
+ writer.WriteLine("RegisterAllExtensions(registry);");
+ foreach (FileDescriptor dependency in Descriptor.Dependencies)
+ {
+ writer.WriteLine("{0}.RegisterAllExtensions(registry);",
+ DescriptorUtil.GetFullUmbrellaClassName(dependency));
+ }
+ writer.WriteLine("return registry;");
+ }
+ else
+ {
+ writer.WriteLine("return null;");
+ }
+ writer.Outdent();
+ writer.WriteLine("};");
+
+ // -----------------------------------------------------------------
+ // Invoke internalBuildGeneratedFileFrom() to build the file.
+ writer.WriteLine("pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,");
+ writer.WriteLine(" new pbd::FileDescriptor[] {");
+ foreach (FileDescriptor dependency in Descriptor.Dependencies)
+ {
+ writer.WriteLine(" {0}.Descriptor, ", DescriptorUtil.GetFullUmbrellaClassName(dependency));
+ }
+ writer.WriteLine(" }, assigner);");
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine("#endregion");
+ writer.WriteLine();
+ }
+
+ private void WriteLiteExtensions(TextGenerator writer)
+ {
+ writer.WriteLine("#region Extensions");
+ writer.WriteLine("internal static readonly object Descriptor;");
+ writer.WriteLine("static {0}() {{", Descriptor.CSharpOptions.UmbrellaClassname);
+ writer.Indent();
+ writer.WriteLine("Descriptor = null;");
+
+ foreach (MessageDescriptor message in Descriptor.MessageTypes)
+ {
+ new MessageGenerator(message).GenerateStaticVariableInitializers(writer);
+ }
+ foreach (FieldDescriptor extension in Descriptor.Extensions)
+ {
+ new ExtensionGenerator(extension).GenerateStaticVariableInitializers(writer);
+ }
+ writer.Outdent();
+ writer.WriteLine("}");
+ writer.WriteLine("#endregion");
+ writer.WriteLine();
+ }
+ }
+} \ No newline at end of file
diff --git a/csharp/src/ProtoGen/app.config b/csharp/src/ProtoGen/app.config
new file mode 100644
index 00000000..89b324bf
--- /dev/null
+++ b/csharp/src/ProtoGen/app.config
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <startup useLegacyV2RuntimeActivationPolicy="true">
+ <supportedRuntime version="v2.0.50727" />
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" />
+ </startup>
+</configuration> \ No newline at end of file
diff --git a/csharp/src/ProtoGen/protoc-gen-cs.csproj b/csharp/src/ProtoGen/protoc-gen-cs.csproj
new file mode 100644
index 00000000..fdc88cc2
--- /dev/null
+++ b/csharp/src/ProtoGen/protoc-gen-cs.csproj
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <EnvironmentFlavor>CLIENTPROFILE</EnvironmentFlavor>
+ <EnvironmentTemplate>NET35</EnvironmentTemplate>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{250ADE34-82FD-4BAE-86D5-985FBE589C4B}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Google.ProtocolBuffers.ProtoGen</RootNamespace>
+ <AssemblyName>protoc-gen-cs</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\..\keys\Google.ProtocolBuffers.snk</AssemblyOriginatorKeyFile>
+ <StartupObject>Google.ProtocolBuffers.ProtoGen.ProtocGenCs</StartupObject>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\NET35\Debug</OutputPath>
+ <IntermediateOutputPath>obj\NET35\Debug\</IntermediateOutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <NoStdLib>true</NoStdLib>
+ <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\NET35\Release</OutputPath>
+ <IntermediateOutputPath>obj\NET35\Release\</IntermediateOutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
+ <NoStdLib>true</NoStdLib>
+ <GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="mscorlib" />
+ <Reference Include="System" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="DescriptorUtil.cs" />
+ <Compile Include="EnumFieldGenerator.cs" />
+ <Compile Include="EnumGenerator.cs" />
+ <Compile Include="ExtensionGenerator.cs" />
+ <Compile Include="FieldGeneratorBase.cs" />
+ <Compile Include="IFieldSourceGenerator.cs" />
+ <Compile Include="ISourceGenerator.cs" />
+ <Compile Include="MessageFieldGenerator.cs" />
+ <Compile Include="MessageGenerator.cs" />
+ <Compile Include="PluginProtoFile.cs" />
+ <Compile Include="PrimitiveFieldGenerator.cs" />
+ <Compile Include="ProtocGenCs.cs" />
+ <Compile Include="RepeatedEnumFieldGenerator.cs" />
+ <Compile Include="RepeatedMessageFieldGenerator.cs" />
+ <Compile Include="RepeatedPrimitiveFieldGenerator.cs" />
+ <Compile Include="ServiceGenerator.cs" />
+ <Compile Include="DependencyResolutionException.cs" />
+ <Compile Include="Generator.cs" />
+ <Compile Include="GeneratorOptions.cs" />
+ <Compile Include="Helpers.cs" />
+ <Compile Include="InvalidOptionsException.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="ServiceInterfaceGenerator.cs" />
+ <Compile Include="SourceGeneratorBase.cs" />
+ <Compile Include="SourceGenerators.cs" />
+ <Compile Include="UmbrellaClassGenerator.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\ProtocolBuffers.Serialization\ProtocolBuffers.Serialization.csproj">
+ <Project>{231391af-449c-4a39-986c-ad7f270f4750}</Project>
+ <Name>ProtocolBuffers.Serialization</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\ProtocolBuffers\ProtocolBuffers.csproj">
+ <Project>{6908BDCE-D925-43F3-94AC-A531E6DF2591}</Project>
+ <Name>ProtocolBuffers</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file