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 (at) 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 <io.h> 40 #include <fcntl.h> 41 #ifndef STDIN_FILENO 42 #define STDIN_FILENO 0 43 #endif 44 #ifndef STDOUT_FILENO 45 #define STDOUT_FILENO 1 46 #endif 47 #else 48 #include <unistd.h> 49 #endif 50 51 #include <google/protobuf/stubs/logging.h> 52 #include <google/protobuf/stubs/common.h> 53 #include <google/protobuf/compiler/plugin.pb.h> 54 #include <google/protobuf/compiler/code_generator.h> 55 #include <google/protobuf/descriptor.h> 56 #include <google/protobuf/io/zero_copy_stream_impl.h> 57 58 59 namespace google { 60 namespace protobuf { 61 namespace compiler { 62 63 class GeneratorResponseContext : public GeneratorContext { 64 public: 65 GeneratorResponseContext(CodeGeneratorResponse* response, 66 const vector<const FileDescriptor*>& parsed_files) 67 : response_(response), 68 parsed_files_(parsed_files) {} 69 virtual ~GeneratorResponseContext() {} 70 71 // implements GeneratorContext -------------------------------------- 72 73 virtual io::ZeroCopyOutputStream* Open(const string& filename) { 74 CodeGeneratorResponse::File* file = response_->add_file(); 75 file->set_name(filename); 76 return new io::StringOutputStream(file->mutable_content()); 77 } 78 79 virtual io::ZeroCopyOutputStream* OpenForInsert( 80 const string& filename, const string& insertion_point) { 81 CodeGeneratorResponse::File* file = response_->add_file(); 82 file->set_name(filename); 83 file->set_insertion_point(insertion_point); 84 return new io::StringOutputStream(file->mutable_content()); 85 } 86 87 void ListParsedFiles(vector<const FileDescriptor*>* output) { 88 *output = parsed_files_; 89 } 90 91 private: 92 CodeGeneratorResponse* response_; 93 const vector<const FileDescriptor*>& parsed_files_; 94 }; 95 96 bool GenerateCode(const CodeGeneratorRequest& request, 97 const CodeGenerator& generator, CodeGeneratorResponse* response, 98 string* error_msg) { 99 DescriptorPool pool; 100 for (int i = 0; i < request.proto_file_size(); i++) { 101 const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); 102 if (file == NULL) { 103 // BuildFile() already wrote an error message. 104 return false; 105 } 106 } 107 108 vector<const FileDescriptor*> parsed_files; 109 for (int i = 0; i < request.file_to_generate_size(); i++) { 110 parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); 111 if (parsed_files.back() == NULL) { 112 *error_msg = "protoc asked plugin to generate a file but " 113 "did not provide a descriptor for the file: " + 114 request.file_to_generate(i); 115 return false; 116 } 117 } 118 119 GeneratorResponseContext context(response, parsed_files); 120 121 if (generator.HasGenerateAll()) { 122 string error; 123 bool succeeded = generator.GenerateAll( 124 parsed_files, request.parameter(), &context, &error); 125 126 if (!succeeded && error.empty()) { 127 error = "Code generator returned false but provided no error " 128 "description."; 129 } 130 if (!error.empty()) { 131 response->set_error(error); 132 } 133 } else { 134 for (int i = 0; i < parsed_files.size(); i++) { 135 const FileDescriptor* file = parsed_files[i]; 136 137 string error; 138 bool succeeded = generator.Generate( 139 file, request.parameter(), &context, &error); 140 141 if (!succeeded && error.empty()) { 142 error = "Code generator returned false but provided no error " 143 "description."; 144 } 145 if (!error.empty()) { 146 response->set_error(file->name() + ": " + error); 147 break; 148 } 149 } 150 } 151 152 return true; 153 } 154 155 int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { 156 157 if (argc > 1) { 158 std::cerr << argv[0] << ": Unknown option: " << argv[1] << std::endl; 159 return 1; 160 } 161 162 #ifdef _WIN32 163 _setmode(STDIN_FILENO, _O_BINARY); 164 _setmode(STDOUT_FILENO, _O_BINARY); 165 #endif 166 167 CodeGeneratorRequest request; 168 if (!request.ParseFromFileDescriptor(STDIN_FILENO)) { 169 std::cerr << argv[0] << ": protoc sent unparseable request to plugin." 170 << std::endl; 171 return 1; 172 } 173 174 string error_msg; 175 CodeGeneratorResponse response; 176 177 if (GenerateCode(request, *generator, &response, &error_msg)) { 178 if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { 179 std::cerr << argv[0] << ": Error writing to stdout." << std::endl; 180 return 1; 181 } 182 } else { 183 if (!error_msg.empty()) { 184 std::cerr << argv[0] << ": " << error_msg << std::endl; 185 } 186 return 1; 187 } 188 189 return 0; 190 } 191 192 } // namespace compiler 193 } // namespace protobuf 194 } // namespace google 195