Free cookie consent management tool by TermsFeed Policy Generator

source: branches/ParameterBinding/HeuristicLab.ExtLibs/HeuristicLab.ProtobufCS/0.9.1/ProtobufCS/src/ProtoGen/Generator.cs @ 13401

Last change on this file since 13401 was 4068, checked in by swagner, 14 years ago

Sorted usings and removed unused usings in entire solution (#1094)

File size: 7.2 KB
Line 
1#region Copyright notice and license
2// Protocol Buffers - Google's data interchange format
3// Copyright 2008 Google Inc.  All rights reserved.
4// http://github.com/jskeet/dotnet-protobufs/
5// Original C++/Java/Python code:
6// http://code.google.com/p/protobuf/
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are
10// met:
11//
12//     * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14//     * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18//     * Neither the name of Google Inc. nor the names of its
19// contributors may be used to endorse or promote products derived from
20// this software without specific prior written permission.
21//
22// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33#endregion
34
35using System.Collections.Generic;
36using System.IO;
37using System.Text;
38using Google.ProtocolBuffers.Collections;
39using Google.ProtocolBuffers.DescriptorProtos;
40using Google.ProtocolBuffers.Descriptors;
41
42namespace Google.ProtocolBuffers.ProtoGen {
43  /// <summary>
44  /// Code generator for protocol buffers. Only C# is supported at the moment.
45  /// </summary>
46  public sealed class Generator {
47
48    readonly GeneratorOptions options;
49
50    private Generator(GeneratorOptions options) {
51      options.Validate();
52      this.options = options;
53    }
54
55    /// <summary>
56    /// Returns a generator configured with the specified options.
57    /// </summary>
58    public static Generator CreateGenerator(GeneratorOptions options) {
59      return new Generator(options);
60    }
61
62    public void Generate() {
63      foreach (string inputFile in options.InputFiles) {
64        FileDescriptorSet descriptorProtos;
65        ExtensionRegistry extensionRegistry = ExtensionRegistry.CreateInstance();
66        extensionRegistry.Add(CSharpOptions.CSharpFileOptions);
67        extensionRegistry.Add(CSharpOptions.CSharpFieldOptions);
68        using (Stream inputStream = File.OpenRead(inputFile)) {
69          descriptorProtos = FileDescriptorSet.ParseFrom(inputStream, extensionRegistry);
70        }
71        IList<FileDescriptor> descriptors = ConvertDescriptors(descriptorProtos);
72
73        foreach (FileDescriptor descriptor in descriptors) {
74          Generate(descriptor);
75        }
76      }
77    }
78
79    /// <summary>
80    /// Generates code for a particular file. All dependencies must
81    /// already have been resolved.
82    /// </summary>
83    private void Generate(FileDescriptor descriptor) {
84      UmbrellaClassGenerator ucg = new UmbrellaClassGenerator(descriptor);
85      using (TextWriter textWriter = File.CreateText(GetOutputFile(descriptor))) {
86        TextGenerator writer = new TextGenerator(textWriter);
87        ucg.Generate(writer);
88      }
89    }
90
91    private string GetOutputFile(FileDescriptor descriptor) {
92      CSharpFileOptions fileOptions = descriptor.CSharpOptions;
93      string filename = descriptor.CSharpOptions.UmbrellaClassname + ".cs";
94      string outputDirectory = options.OutputDirectory;
95      if (fileOptions.ExpandNamespaceDirectories) {
96        string package = fileOptions.Namespace;
97        if (!string.IsNullOrEmpty(package)) {
98          string[] bits = package.Split('.');
99          foreach (string bit in bits) {
100            outputDirectory = Path.Combine(outputDirectory, bit);
101          }
102          Directory.CreateDirectory(outputDirectory);
103        }
104      }
105      return Path.Combine(outputDirectory, filename);
106    }
107
108    /// <summary>
109    /// Resolves any dependencies and converts FileDescriptorProtos into FileDescriptors.
110    /// The list returned is in the same order as the protos are listed in the descriptor set.
111    /// Note: this method is internal rather than private to allow testing.
112    /// </summary>
113    /// <exception cref="DependencyResolutionException">Not all dependencies could be resolved.</exception>
114    internal static IList<FileDescriptor> ConvertDescriptors(FileDescriptorSet descriptorProtos) {
115      // Simple strategy: Keep going through the list of protos to convert, only doing ones where
116      // we've already converted all the dependencies, until we get to a stalemate
117      IList<FileDescriptorProto> fileList = descriptorProtos.FileList;
118      FileDescriptor[] converted = new FileDescriptor[fileList.Count];
119
120      Dictionary<string, FileDescriptor> convertedMap = new Dictionary<string, FileDescriptor>();
121
122      int totalConverted = 0;
123
124      bool madeProgress = true;
125      while (madeProgress && totalConverted < converted.Length) {
126        madeProgress = false;
127        for (int i = 0; i < converted.Length; i++) {
128          if (converted[i] != null) {
129            // Already done this one
130            continue;
131          }
132          FileDescriptorProto candidate = fileList[i];
133          FileDescriptor[] dependencies = new FileDescriptor[candidate.DependencyList.Count];
134          bool foundAllDependencies = true;
135          for (int j = 0; j < dependencies.Length; j++) {
136            if (!convertedMap.TryGetValue(candidate.DependencyList[j], out dependencies[j])) {
137              foundAllDependencies = false;
138              break;
139            }
140          }
141          if (!foundAllDependencies) {
142            continue;
143          }
144          madeProgress = true;
145          totalConverted++;
146          converted[i] = FileDescriptor.BuildFrom(candidate, dependencies);
147          convertedMap[candidate.Name] = converted[i];
148        }
149      }
150      if (!madeProgress) {
151        StringBuilder remaining = new StringBuilder();
152        for (int i = 0; i < converted.Length; i++) {
153          if (converted[i] == null) {
154            if (remaining.Length != 0) {
155              remaining.Append(", ");
156            }
157            FileDescriptorProto failure = fileList[i];
158            remaining.Append(failure.Name);
159            remaining.Append(":");
160            foreach (string dependency in failure.DependencyList) {
161              if (!convertedMap.ContainsKey(dependency)) {
162                remaining.Append(" ");
163                remaining.Append(dependency);
164              }
165            }
166            remaining.Append(";");
167          }
168        }
169        throw new DependencyResolutionException("Unable to resolve all dependencies: " + remaining);
170      }
171      return Lists.AsReadOnly(converted);
172    }
173  }
174}
Note: See TracBrowser for help on using the repository browser.