1 #include "Errors.h" 2 #include "stream_proto_utils.h" 3 #include "string_utils.h" 4 5 #include <iomanip> 6 #include <iostream> 7 #include <sstream> 8 9 using namespace android::stream_proto; 10 using namespace google::protobuf::io; 11 using namespace std; 12 13 const bool GENERATE_MAPPING = true; 14 15 static string 16 make_filename(const FileDescriptorProto& file_descriptor) 17 { 18 return file_descriptor.name() + ".h"; 19 } 20 21 static void 22 write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent) 23 { 24 const int N = enu.value_size(); 25 text << indent << "// enum " << enu.name() << endl; 26 for (int i=0; i<N; i++) { 27 const EnumValueDescriptorProto& value = enu.value(i); 28 text << indent << "const int " 29 << make_constant_name(value.name()) 30 << " = " << value.number() << ";" << endl; 31 } 32 33 if (GENERATE_MAPPING) { 34 string name = make_constant_name(enu.name()); 35 string prefix = name + "_"; 36 text << indent << "const int _ENUM_" << name << "_COUNT = " << N << ";" << endl; 37 text << indent << "const char* _ENUM_" << name << "_NAMES[" << N << "] = {" << endl; 38 for (int i=0; i<N; i++) { 39 text << indent << INDENT << "\"" << stripPrefix(enu.value(i).name(), prefix) << "\"," << endl; 40 } 41 text << indent << "};" << endl; 42 text << indent << "const int _ENUM_" << name << "_VALUES[" << N << "] = {" << endl; 43 for (int i=0; i<N; i++) { 44 text << indent << INDENT << make_constant_name(enu.value(i).name()) << "," << endl; 45 } 46 text << indent << "};" << endl; 47 } 48 49 text << endl; 50 } 51 52 static void 53 write_field(stringstream& text, const FieldDescriptorProto& field, const string& indent) 54 { 55 string optional_comment = field.label() == FieldDescriptorProto::LABEL_OPTIONAL 56 ? "optional " : ""; 57 string repeated_comment = field.label() == FieldDescriptorProto::LABEL_REPEATED 58 ? "repeated " : ""; 59 string proto_type = get_proto_type(field); 60 string packed_comment = field.options().packed() 61 ? " [packed=true]" : ""; 62 text << indent << "// " << optional_comment << repeated_comment << proto_type << ' ' 63 << field.name() << " = " << field.number() << packed_comment << ';' << endl; 64 65 text << indent << "const uint64_t " << make_constant_name(field.name()) << " = 0x"; 66 67 ios::fmtflags fmt(text.flags()); 68 text << setfill('0') << setw(16) << hex << get_field_id(field); 69 text.flags(fmt); 70 71 text << "LL;" << endl; 72 73 text << endl; 74 } 75 76 static void 77 write_message(stringstream& text, const DescriptorProto& message, const string& indent) 78 { 79 int N; 80 const string indented = indent + INDENT; 81 82 text << indent << "// message " << message.name() << endl; 83 text << indent << "namespace " << message.name() << " {" << endl; 84 85 // Enums 86 N = message.enum_type_size(); 87 for (int i=0; i<N; i++) { 88 write_enum(text, message.enum_type(i), indented); 89 } 90 91 // Nested classes 92 N = message.nested_type_size(); 93 for (int i=0; i<N; i++) { 94 write_message(text, message.nested_type(i), indented); 95 } 96 97 // Fields 98 N = message.field_size(); 99 for (int i=0; i<N; i++) { 100 write_field(text, message.field(i), indented); 101 } 102 103 if (GENERATE_MAPPING) { 104 N = message.field_size(); 105 text << indented << "const int _FIELD_COUNT = " << N << ";" << endl; 106 text << indented << "const char* _FIELD_NAMES[" << N << "] = {" << endl; 107 for (int i=0; i<N; i++) { 108 text << indented << INDENT << "\"" << message.field(i).name() << "\"," << endl; 109 } 110 text << indented << "};" << endl; 111 text << indented << "const uint64_t _FIELD_IDS[" << N << "] = {" << endl; 112 for (int i=0; i<N; i++) { 113 text << indented << INDENT << make_constant_name(message.field(i).name()) << "," << endl; 114 } 115 text << indented << "};" << endl << endl; 116 } 117 118 text << indent << "} //" << message.name() << endl; 119 text << endl; 120 } 121 122 static void 123 write_header_file(CodeGeneratorResponse* response, const FileDescriptorProto& file_descriptor) 124 { 125 stringstream text; 126 127 text << "// Generated by protoc-gen-cppstream. DO NOT MODIFY." << endl; 128 text << "// source: " << file_descriptor.name() << endl << endl; 129 130 string header = "ANDROID_" + replace_string(file_descriptor.name(), '/', '_'); 131 header = replace_string(header, '.', '_') + "_stream_h"; 132 header = make_constant_name(header); 133 134 text << "#ifndef " << header << endl; 135 text << "#define " << header << endl; 136 text << endl; 137 138 vector<string> namespaces = split(file_descriptor.package(), '.'); 139 for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) { 140 text << "namespace " << *it << " {" << endl; 141 } 142 text << endl; 143 144 size_t N; 145 N = file_descriptor.enum_type_size(); 146 for (size_t i=0; i<N; i++) { 147 write_enum(text, file_descriptor.enum_type(i), ""); 148 } 149 150 N = file_descriptor.message_type_size(); 151 for (size_t i=0; i<N; i++) { 152 write_message(text, file_descriptor.message_type(i), ""); 153 } 154 155 for (vector<string>::iterator it = namespaces.begin(); it != namespaces.end(); it++) { 156 text << "} // " << *it << endl; 157 } 158 159 text << endl; 160 text << "#endif // " << header << endl; 161 162 CodeGeneratorResponse::File* file_response = response->add_file(); 163 file_response->set_name(make_filename(file_descriptor)); 164 file_response->set_content(text.str()); 165 } 166 167 int main(int argc, char const *argv[]) 168 { 169 (void)argc; 170 (void)argv; 171 172 GOOGLE_PROTOBUF_VERIFY_VERSION; 173 174 CodeGeneratorRequest request; 175 CodeGeneratorResponse response; 176 177 // Read the request 178 request.ParseFromIstream(&cin); 179 180 // Build the files we need. 181 const int N = request.proto_file_size(); 182 for (int i=0; i<N; i++) { 183 const FileDescriptorProto& file_descriptor = request.proto_file(i); 184 if (should_generate_for_file(request, file_descriptor.name())) { 185 write_header_file(&response, file_descriptor); 186 } 187 } 188 189 // If we had errors, don't write the response. Print the errors and exit. 190 if (ERRORS.HasErrors()) { 191 ERRORS.Print(); 192 return 1; 193 } 194 195 // If we didn't have errors, write the response and exit happily. 196 response.SerializeToOstream(&cout); 197 198 /* code */ 199 return 0; 200 } 201