1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // http://code.google.com/p/protobuf/ 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 // Based on original Protocol Buffers design by 33 // Sanjay Ghemawat, Jeff Dean, and others. 34 35 #include <limits> 36 #include <vector> 37 38 #include <google/protobuf/compiler/javanano/javanano_helpers.h> 39 #include <google/protobuf/compiler/javanano/javanano_params.h> 40 #include <google/protobuf/descriptor.pb.h> 41 #include <google/protobuf/stubs/hash.h> 42 #include <google/protobuf/stubs/strutil.h> 43 #include <google/protobuf/stubs/substitute.h> 44 45 namespace google { 46 namespace protobuf { 47 namespace compiler { 48 namespace javanano { 49 50 const char kThickSeparator[] = 51 "// ===================================================================\n"; 52 const char kThinSeparator[] = 53 "// -------------------------------------------------------------------\n"; 54 55 class RenameKeywords { 56 private: 57 hash_set<string> java_keywords_set_; 58 59 public: 60 RenameKeywords() { 61 static const char* kJavaKeywordsList[] = { 62 // Reserved Java Keywords 63 "abstract", "assert", "boolean", "break", "byte", "case", "catch", 64 "char", "class", "const", "continue", "default", "do", "double", "else", 65 "enum", "extends", "final", "finally", "float", "for", "goto", "if", 66 "implements", "import", "instanceof", "int", "interface", "long", 67 "native", "new", "package", "private", "protected", "public", "return", 68 "short", "static", "strictfp", "super", "switch", "synchronized", 69 "this", "throw", "throws", "transient", "try", "void", "volatile", "while", 70 71 // Reserved Keywords for Literals 72 "false", "null", "true" 73 }; 74 75 for (int i = 0; i < GOOGLE_ARRAYSIZE(kJavaKeywordsList); i++) { 76 java_keywords_set_.insert(kJavaKeywordsList[i]); 77 } 78 } 79 80 // Used to rename the a field name if it's a java keyword. Specifically 81 // this is used to rename the ["name"] or ["capitalized_name"] field params. 82 // (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html) 83 string RenameJavaKeywordsImpl(const string& input) { 84 string result = input; 85 86 if (java_keywords_set_.find(result) != java_keywords_set_.end()) { 87 result += "_"; 88 } 89 90 return result; 91 } 92 93 }; 94 95 static RenameKeywords sRenameKeywords; 96 97 namespace { 98 99 const char* kDefaultPackage = ""; 100 101 const string& FieldName(const FieldDescriptor* field) { 102 // Groups are hacky: The name of the field is just the lower-cased name 103 // of the group type. In Java, though, we would like to retain the original 104 // capitalization of the type name. 105 if (field->type() == FieldDescriptor::TYPE_GROUP) { 106 return field->message_type()->name(); 107 } else { 108 return field->name(); 109 } 110 } 111 112 string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) { 113 string result; 114 // Note: I distrust ctype.h due to locales. 115 for (int i = 0; i < input.size(); i++) { 116 if ('a' <= input[i] && input[i] <= 'z') { 117 if (cap_next_letter) { 118 result += input[i] + ('A' - 'a'); 119 } else { 120 result += input[i]; 121 } 122 cap_next_letter = false; 123 } else if ('A' <= input[i] && input[i] <= 'Z') { 124 if (i == 0 && !cap_next_letter) { 125 // Force first letter to lower-case unless explicitly told to 126 // capitalize it. 127 result += input[i] + ('a' - 'A'); 128 } else { 129 // Capital letters after the first are left as-is. 130 result += input[i]; 131 } 132 cap_next_letter = false; 133 } else if ('0' <= input[i] && input[i] <= '9') { 134 result += input[i]; 135 cap_next_letter = true; 136 } else { 137 cap_next_letter = true; 138 } 139 } 140 return result; 141 } 142 143 } // namespace 144 145 string UnderscoresToCamelCase(const FieldDescriptor* field) { 146 return UnderscoresToCamelCaseImpl(FieldName(field), false); 147 } 148 149 string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { 150 return UnderscoresToCamelCaseImpl(FieldName(field), true); 151 } 152 153 string UnderscoresToCamelCase(const MethodDescriptor* method) { 154 return UnderscoresToCamelCaseImpl(method->name(), false); 155 } 156 157 string RenameJavaKeywords(const string& input) { 158 return sRenameKeywords.RenameJavaKeywordsImpl(input); 159 } 160 161 string StripProto(const string& filename) { 162 if (HasSuffixString(filename, ".protodevel")) { 163 return StripSuffixString(filename, ".protodevel"); 164 } else { 165 return StripSuffixString(filename, ".proto"); 166 } 167 } 168 169 string FileClassName(const Params& params, const FileDescriptor* file) { 170 if (params.has_java_outer_classname(file->name())) { 171 return params.java_outer_classname(file->name()); 172 } else { 173 // Use the filename itself with underscores removed 174 // and a CamelCase style name. 175 string basename; 176 string::size_type last_slash = file->name().find_last_of('/'); 177 if (last_slash == string::npos) { 178 basename = file->name(); 179 } else { 180 basename = file->name().substr(last_slash + 1); 181 } 182 return UnderscoresToCamelCaseImpl(StripProto(basename), true); 183 } 184 } 185 186 string FileJavaPackage(const Params& params, const FileDescriptor* file) { 187 if (params.has_java_package(file->name())) { 188 return params.java_package(file->name()); 189 } else { 190 string result = kDefaultPackage; 191 if (!file->package().empty()) { 192 if (!result.empty()) result += '.'; 193 result += file->package(); 194 } 195 return result; 196 } 197 } 198 199 bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) { 200 // If java_multiple_files is false, the outer class is always needed. 201 if (!params.java_multiple_files(file->name())) { 202 return true; 203 } 204 205 // File-scope extensions need the outer class as the scope. 206 if (file->extension_count() != 0) { 207 return true; 208 } 209 210 // If container interfaces are not generated, file-scope enums need the 211 // outer class as the scope. 212 if (file->enum_type_count() != 0 && !params.java_enum_style()) { 213 return true; 214 } 215 216 return false; 217 } 218 219 string ToJavaName(const Params& params, const string& name, bool is_class, 220 const Descriptor* parent, const FileDescriptor* file) { 221 string result; 222 if (parent != NULL) { 223 result.append(ClassName(params, parent)); 224 } else if (is_class && params.java_multiple_files(file->name())) { 225 result.append(FileJavaPackage(params, file)); 226 } else { 227 result.append(ClassName(params, file)); 228 } 229 if (!result.empty()) result.append(1, '.'); 230 result.append(RenameJavaKeywords(name)); 231 return result; 232 } 233 234 string ClassName(const Params& params, const FileDescriptor* descriptor) { 235 string result = FileJavaPackage(params, descriptor); 236 if (!result.empty()) result += '.'; 237 result += FileClassName(params, descriptor); 238 return result; 239 } 240 241 string ClassName(const Params& params, const EnumDescriptor* descriptor) { 242 const Descriptor* parent = descriptor->containing_type(); 243 // When using Java enum style, an enum's class name contains the enum name. 244 // Use the standard ToJavaName translation. 245 if (params.java_enum_style()) { 246 return ToJavaName(params, descriptor->name(), true, parent, 247 descriptor->file()); 248 } 249 // Otherwise the enum members are accessed from the enclosing class. 250 if (parent != NULL) { 251 return ClassName(params, parent); 252 } else { 253 return ClassName(params, descriptor->file()); 254 } 255 } 256 257 string FieldConstantName(const FieldDescriptor *field) { 258 string name = field->name() + "_FIELD_NUMBER"; 259 UpperString(&name); 260 return name; 261 } 262 263 string FieldDefaultConstantName(const FieldDescriptor *field) { 264 return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default"; 265 } 266 267 void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { 268 // We don't want to print group bodies so we cut off after the first line 269 // (the second line for extensions). 270 string def = field->DebugString(); 271 string::size_type first_line_end = def.find_first_of('\n'); 272 printer->Print("// $def$\n", 273 "def", def.substr(0, first_line_end)); 274 if (field->is_extension()) { 275 string::size_type second_line_start = first_line_end + 1; 276 string::size_type second_line_length = 277 def.find('\n', second_line_start) - second_line_start; 278 printer->Print("// $def$\n", 279 "def", def.substr(second_line_start, second_line_length)); 280 } 281 } 282 283 JavaType GetJavaType(FieldDescriptor::Type field_type) { 284 switch (field_type) { 285 case FieldDescriptor::TYPE_INT32: 286 case FieldDescriptor::TYPE_UINT32: 287 case FieldDescriptor::TYPE_SINT32: 288 case FieldDescriptor::TYPE_FIXED32: 289 case FieldDescriptor::TYPE_SFIXED32: 290 return JAVATYPE_INT; 291 292 case FieldDescriptor::TYPE_INT64: 293 case FieldDescriptor::TYPE_UINT64: 294 case FieldDescriptor::TYPE_SINT64: 295 case FieldDescriptor::TYPE_FIXED64: 296 case FieldDescriptor::TYPE_SFIXED64: 297 return JAVATYPE_LONG; 298 299 case FieldDescriptor::TYPE_FLOAT: 300 return JAVATYPE_FLOAT; 301 302 case FieldDescriptor::TYPE_DOUBLE: 303 return JAVATYPE_DOUBLE; 304 305 case FieldDescriptor::TYPE_BOOL: 306 return JAVATYPE_BOOLEAN; 307 308 case FieldDescriptor::TYPE_STRING: 309 return JAVATYPE_STRING; 310 311 case FieldDescriptor::TYPE_BYTES: 312 return JAVATYPE_BYTES; 313 314 case FieldDescriptor::TYPE_ENUM: 315 return JAVATYPE_ENUM; 316 317 case FieldDescriptor::TYPE_GROUP: 318 case FieldDescriptor::TYPE_MESSAGE: 319 return JAVATYPE_MESSAGE; 320 321 // No default because we want the compiler to complain if any new 322 // types are added. 323 } 324 325 GOOGLE_LOG(FATAL) << "Can't get here."; 326 return JAVATYPE_INT; 327 } 328 329 string PrimitiveTypeName(JavaType type) { 330 switch (type) { 331 case JAVATYPE_INT : return "int"; 332 case JAVATYPE_LONG : return "long"; 333 case JAVATYPE_FLOAT : return "float"; 334 case JAVATYPE_DOUBLE : return "double"; 335 case JAVATYPE_BOOLEAN: return "boolean"; 336 case JAVATYPE_STRING : return "java.lang.String"; 337 case JAVATYPE_BYTES : return "byte[]"; 338 case JAVATYPE_ENUM : return "int"; 339 case JAVATYPE_MESSAGE: return NULL; 340 341 // No default because we want the compiler to complain if any new 342 // JavaTypes are added. 343 } 344 345 GOOGLE_LOG(FATAL) << "Can't get here."; 346 return NULL; 347 } 348 349 string BoxedPrimitiveTypeName(JavaType type) { 350 switch (type) { 351 case JAVATYPE_INT : return "java.lang.Integer"; 352 case JAVATYPE_LONG : return "java.lang.Long"; 353 case JAVATYPE_FLOAT : return "java.lang.Float"; 354 case JAVATYPE_DOUBLE : return "java.lang.Double"; 355 case JAVATYPE_BOOLEAN: return "java.lang.Boolean"; 356 case JAVATYPE_STRING : return "java.lang.String"; 357 case JAVATYPE_BYTES : return "byte[]"; 358 case JAVATYPE_ENUM : return "java.lang.Integer"; 359 case JAVATYPE_MESSAGE: return NULL; 360 361 // No default because we want the compiler to complain if any new 362 // JavaTypes are added. 363 } 364 365 GOOGLE_LOG(FATAL) << "Can't get here."; 366 return NULL; 367 } 368 369 string EmptyArrayName(const Params& params, const FieldDescriptor* field) { 370 switch (GetJavaType(field)) { 371 case JAVATYPE_INT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; 372 case JAVATYPE_LONG : return "com.google.protobuf.nano.WireFormatNano.EMPTY_LONG_ARRAY"; 373 case JAVATYPE_FLOAT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_FLOAT_ARRAY"; 374 case JAVATYPE_DOUBLE : return "com.google.protobuf.nano.WireFormatNano.EMPTY_DOUBLE_ARRAY"; 375 case JAVATYPE_BOOLEAN: return "com.google.protobuf.nano.WireFormatNano.EMPTY_BOOLEAN_ARRAY"; 376 case JAVATYPE_STRING : return "com.google.protobuf.nano.WireFormatNano.EMPTY_STRING_ARRAY"; 377 case JAVATYPE_BYTES : return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES_ARRAY"; 378 case JAVATYPE_ENUM : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; 379 case JAVATYPE_MESSAGE: return ClassName(params, field->message_type()) + ".EMPTY_ARRAY"; 380 381 // No default because we want the compiler to complain if any new 382 // JavaTypes are added. 383 } 384 385 GOOGLE_LOG(FATAL) << "Can't get here."; 386 return ""; 387 } 388 389 string DefaultValue(const Params& params, const FieldDescriptor* field) { 390 if (field->label() == FieldDescriptor::LABEL_REPEATED) { 391 return EmptyArrayName(params, field); 392 } 393 394 if (params.use_reference_types_for_primitives()) { 395 return "null"; 396 } 397 398 // Switch on cpp_type since we need to know which default_value_* method 399 // of FieldDescriptor to call. 400 switch (field->cpp_type()) { 401 case FieldDescriptor::CPPTYPE_INT32: 402 return SimpleItoa(field->default_value_int32()); 403 case FieldDescriptor::CPPTYPE_UINT32: 404 // Need to print as a signed int since Java has no unsigned. 405 return SimpleItoa(static_cast<int32>(field->default_value_uint32())); 406 case FieldDescriptor::CPPTYPE_INT64: 407 return SimpleItoa(field->default_value_int64()) + "L"; 408 case FieldDescriptor::CPPTYPE_UINT64: 409 return SimpleItoa(static_cast<int64>(field->default_value_uint64())) + 410 "L"; 411 case FieldDescriptor::CPPTYPE_DOUBLE: { 412 double value = field->default_value_double(); 413 if (value == numeric_limits<double>::infinity()) { 414 return "Double.POSITIVE_INFINITY"; 415 } else if (value == -numeric_limits<double>::infinity()) { 416 return "Double.NEGATIVE_INFINITY"; 417 } else if (value != value) { 418 return "Double.NaN"; 419 } else { 420 return SimpleDtoa(value) + "D"; 421 } 422 } 423 case FieldDescriptor::CPPTYPE_FLOAT: { 424 float value = field->default_value_float(); 425 if (value == numeric_limits<float>::infinity()) { 426 return "Float.POSITIVE_INFINITY"; 427 } else if (value == -numeric_limits<float>::infinity()) { 428 return "Float.NEGATIVE_INFINITY"; 429 } else if (value != value) { 430 return "Float.NaN"; 431 } else { 432 return SimpleFtoa(value) + "F"; 433 } 434 } 435 case FieldDescriptor::CPPTYPE_BOOL: 436 return field->default_value_bool() ? "true" : "false"; 437 case FieldDescriptor::CPPTYPE_STRING: 438 if (!field->default_value_string().empty()) { 439 // Point it to the static final in the generated code. 440 return FieldDefaultConstantName(field); 441 } else { 442 if (field->type() == FieldDescriptor::TYPE_BYTES) { 443 return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES"; 444 } else { 445 return "\"\""; 446 } 447 } 448 449 case FieldDescriptor::CPPTYPE_ENUM: 450 return ClassName(params, field->enum_type()) + "." + 451 RenameJavaKeywords(field->default_value_enum()->name()); 452 453 case FieldDescriptor::CPPTYPE_MESSAGE: 454 return "null"; 455 456 // No default because we want the compiler to complain if any new 457 // types are added. 458 } 459 460 GOOGLE_LOG(FATAL) << "Can't get here."; 461 return ""; 462 } 463 464 465 static const char* kBitMasks[] = { 466 "0x00000001", 467 "0x00000002", 468 "0x00000004", 469 "0x00000008", 470 "0x00000010", 471 "0x00000020", 472 "0x00000040", 473 "0x00000080", 474 475 "0x00000100", 476 "0x00000200", 477 "0x00000400", 478 "0x00000800", 479 "0x00001000", 480 "0x00002000", 481 "0x00004000", 482 "0x00008000", 483 484 "0x00010000", 485 "0x00020000", 486 "0x00040000", 487 "0x00080000", 488 "0x00100000", 489 "0x00200000", 490 "0x00400000", 491 "0x00800000", 492 493 "0x01000000", 494 "0x02000000", 495 "0x04000000", 496 "0x08000000", 497 "0x10000000", 498 "0x20000000", 499 "0x40000000", 500 "0x80000000", 501 }; 502 503 string GetBitFieldName(int index) { 504 string var_name = "bitField"; 505 var_name += SimpleItoa(index); 506 var_name += "_"; 507 return var_name; 508 } 509 510 string GetBitFieldNameForBit(int bit_index) { 511 return GetBitFieldName(bit_index / 32); 512 } 513 514 string GenerateGetBit(int bit_index) { 515 string var_name = GetBitFieldNameForBit(bit_index); 516 int bit_in_var_index = bit_index % 32; 517 518 string mask = kBitMasks[bit_in_var_index]; 519 string result = "((" + var_name + " & " + mask + ") != 0)"; 520 return result; 521 } 522 523 string GenerateSetBit(int bit_index) { 524 string var_name = GetBitFieldNameForBit(bit_index); 525 int bit_in_var_index = bit_index % 32; 526 527 string mask = kBitMasks[bit_in_var_index]; 528 string result = var_name + " |= " + mask; 529 return result; 530 } 531 532 string GenerateClearBit(int bit_index) { 533 string var_name = GetBitFieldNameForBit(bit_index); 534 int bit_in_var_index = bit_index % 32; 535 536 string mask = kBitMasks[bit_in_var_index]; 537 string result = var_name + " = (" + var_name + " & ~" + mask + ")"; 538 return result; 539 } 540 541 string GenerateDifferentBit(int bit_index) { 542 string var_name = GetBitFieldNameForBit(bit_index); 543 int bit_in_var_index = bit_index % 32; 544 545 string mask = kBitMasks[bit_in_var_index]; 546 string result = "((" + var_name + " & " + mask 547 + ") != (other." + var_name + " & " + mask + "))"; 548 return result; 549 } 550 551 void SetBitOperationVariables(const string name, 552 int bitIndex, map<string, string>* variables) { 553 (*variables)["get_" + name] = GenerateGetBit(bitIndex); 554 (*variables)["set_" + name] = GenerateSetBit(bitIndex); 555 (*variables)["clear_" + name] = GenerateClearBit(bitIndex); 556 (*variables)["different_" + name] = GenerateDifferentBit(bitIndex); 557 } 558 559 } // namespace javanano 560 } // namespace compiler 561 } // namespace protobuf 562 } // namespace google 563