• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // Author: kenton@google.com (Kenton Varda)
32 
33 #include <google/protobuf/compiler/plugin.h>
34 
35 #include <iostream>
36 #include <set>
37 
38 #ifdef _WIN32
39 #include <fcntl.h>
40 #else
41 #include <unistd.h>
42 #endif
43 
44 #include <google/protobuf/stubs/logging.h>
45 #include <google/protobuf/stubs/common.h>
46 #include <google/protobuf/compiler/plugin.pb.h>
47 #include <google/protobuf/compiler/code_generator.h>
48 #include <google/protobuf/io/zero_copy_stream_impl.h>
49 #include <google/protobuf/descriptor.h>
50 #include <google/protobuf/io/io_win32.h>
51 
52 
53 namespace google {
54 namespace protobuf {
55 namespace compiler {
56 
57 #if defined(_WIN32)
58 // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
59 // them like we do below.
60 using google::protobuf::io::win32::setmode;
61 #endif
62 
63 class GeneratorResponseContext : public GeneratorContext {
64  public:
GeneratorResponseContext(const Version & compiler_version,CodeGeneratorResponse * response,const std::vector<const FileDescriptor * > & parsed_files)65   GeneratorResponseContext(
66       const Version& compiler_version, CodeGeneratorResponse* response,
67       const std::vector<const FileDescriptor*>& parsed_files)
68       : compiler_version_(compiler_version),
69         response_(response),
70         parsed_files_(parsed_files) {}
~GeneratorResponseContext()71   virtual ~GeneratorResponseContext() {}
72 
73   // implements GeneratorContext --------------------------------------
74 
Open(const std::string & filename)75   virtual io::ZeroCopyOutputStream* Open(const std::string& filename) {
76     CodeGeneratorResponse::File* file = response_->add_file();
77     file->set_name(filename);
78     return new io::StringOutputStream(file->mutable_content());
79   }
80 
OpenForInsert(const std::string & filename,const std::string & insertion_point)81   virtual io::ZeroCopyOutputStream* OpenForInsert(
82       const std::string& filename, const std::string& insertion_point) {
83     CodeGeneratorResponse::File* file = response_->add_file();
84     file->set_name(filename);
85     file->set_insertion_point(insertion_point);
86     return new io::StringOutputStream(file->mutable_content());
87   }
88 
ListParsedFiles(std::vector<const FileDescriptor * > * output)89   void ListParsedFiles(std::vector<const FileDescriptor*>* output) {
90     *output = parsed_files_;
91   }
92 
GetCompilerVersion(Version * version) const93   void GetCompilerVersion(Version* version) const {
94     *version = compiler_version_;
95   }
96 
97  private:
98   Version compiler_version_;
99   CodeGeneratorResponse* response_;
100   const std::vector<const FileDescriptor*>& parsed_files_;
101 };
102 
GenerateCode(const CodeGeneratorRequest & request,const CodeGenerator & generator,CodeGeneratorResponse * response,std::string * error_msg)103 bool GenerateCode(const CodeGeneratorRequest& request,
104                   const CodeGenerator& generator,
105                   CodeGeneratorResponse* response, std::string* error_msg) {
106   DescriptorPool pool;
107   for (int i = 0; i < request.proto_file_size(); i++) {
108     const FileDescriptor* file = pool.BuildFile(request.proto_file(i));
109     if (file == NULL) {
110       // BuildFile() already wrote an error message.
111       return false;
112     }
113   }
114 
115   std::vector<const FileDescriptor*> parsed_files;
116   for (int i = 0; i < request.file_to_generate_size(); i++) {
117     parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i)));
118     if (parsed_files.back() == NULL) {
119       *error_msg =
120           "protoc asked plugin to generate a file but "
121           "did not provide a descriptor for the file: " +
122           request.file_to_generate(i);
123       return false;
124     }
125   }
126 
127   GeneratorResponseContext context(request.compiler_version(), response,
128                                    parsed_files);
129 
130 
131   std::string error;
132   bool succeeded = generator.GenerateAll(parsed_files, request.parameter(),
133                                          &context, &error);
134 
135   response->set_supported_features(generator.GetSupportedFeatures());
136 
137   if (!succeeded && error.empty()) {
138     error =
139         "Code generator returned false but provided no error "
140         "description.";
141   }
142   if (!error.empty()) {
143     response->set_error(error);
144   }
145 
146   return true;
147 }
148 
PluginMain(int argc,char * argv[],const CodeGenerator * generator)149 int PluginMain(int argc, char* argv[], const CodeGenerator* generator) {
150 
151   if (argc > 1) {
152     std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl;
153     return 1;
154   }
155 
156 #ifdef _WIN32
157   setmode(STDIN_FILENO, _O_BINARY);
158   setmode(STDOUT_FILENO, _O_BINARY);
159 #endif
160 
161   CodeGeneratorRequest request;
162   if (!request.ParseFromFileDescriptor(STDIN_FILENO)) {
163     std::cerr << argv[0] << ": protoc sent unparseable request to plugin."
164               << std::endl;
165     return 1;
166   }
167 
168   std::string error_msg;
169   CodeGeneratorResponse response;
170 
171   if (GenerateCode(request, *generator, &response, &error_msg)) {
172     if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) {
173       std::cerr << argv[0] << ": Error writing to stdout." << std::endl;
174       return 1;
175     }
176   } else {
177     if (!error_msg.empty()) {
178       std::cerr << argv[0] << ": " << error_msg << std::endl;
179     }
180     return 1;
181   }
182 
183   return 0;
184 }
185 
186 }  // namespace compiler
187 }  // namespace protobuf
188 }  // namespace google
189