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 UnderscoresToCamelCase(const OneofDescriptor* oneof) { 158 return UnderscoresToCamelCaseImpl(oneof->name(), false); 159 } 160 161 string UnderscoresToCapitalizedCamelCase(const OneofDescriptor* oneof) { 162 return UnderscoresToCamelCaseImpl(oneof->name(), true); 163 } 164 165 string RenameJavaKeywords(const string& input) { 166 return sRenameKeywords.RenameJavaKeywordsImpl(input); 167 } 168 169 string StripProto(const string& filename) { 170 if (HasSuffixString(filename, ".protodevel")) { 171 return StripSuffixString(filename, ".protodevel"); 172 } else { 173 return StripSuffixString(filename, ".proto"); 174 } 175 } 176 177 string FileClassName(const Params& params, const FileDescriptor* file) { 178 if (params.has_java_outer_classname(file->name())) { 179 return params.java_outer_classname(file->name()); 180 } else { 181 // Use the filename itself with underscores removed 182 // and a CamelCase style name. 183 string basename; 184 string::size_type last_slash = file->name().find_last_of('/'); 185 if (last_slash == string::npos) { 186 basename = file->name(); 187 } else { 188 basename = file->name().substr(last_slash + 1); 189 } 190 return UnderscoresToCamelCaseImpl(StripProto(basename), true); 191 } 192 } 193 194 string FileJavaPackage(const Params& params, const FileDescriptor* file) { 195 if (params.has_java_package(file->name())) { 196 return params.java_package(file->name()); 197 } else { 198 string result = kDefaultPackage; 199 if (!file->package().empty()) { 200 if (!result.empty()) result += '.'; 201 result += file->package(); 202 } 203 204 if (!result.empty()) { 205 result += "."; 206 } 207 result += "nano"; 208 209 return result; 210 } 211 } 212 213 bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) { 214 // If java_multiple_files is false, the outer class is always needed. 215 if (!params.java_multiple_files(file->name())) { 216 return true; 217 } 218 219 // File-scope extensions need the outer class as the scope. 220 if (file->extension_count() != 0) { 221 return true; 222 } 223 224 // If container interfaces are not generated, file-scope enums need the 225 // outer class as the scope. 226 if (file->enum_type_count() != 0 && !params.java_enum_style()) { 227 return true; 228 } 229 230 return false; 231 } 232 233 string ToJavaName(const Params& params, const string& name, bool is_class, 234 const Descriptor* parent, const FileDescriptor* file) { 235 string result; 236 if (parent != NULL) { 237 result.append(ClassName(params, parent)); 238 } else if (is_class && params.java_multiple_files(file->name())) { 239 result.append(FileJavaPackage(params, file)); 240 } else { 241 result.append(ClassName(params, file)); 242 } 243 if (!result.empty()) result.append(1, '.'); 244 result.append(RenameJavaKeywords(name)); 245 return result; 246 } 247 248 string ClassName(const Params& params, const FileDescriptor* descriptor) { 249 string result = FileJavaPackage(params, descriptor); 250 if (!result.empty()) result += '.'; 251 result += FileClassName(params, descriptor); 252 return result; 253 } 254 255 string ClassName(const Params& params, const EnumDescriptor* descriptor) { 256 const Descriptor* parent = descriptor->containing_type(); 257 // When using Java enum style, an enum's class name contains the enum name. 258 // Use the standard ToJavaName translation. 259 if (params.java_enum_style()) { 260 return ToJavaName(params, descriptor->name(), true, parent, 261 descriptor->file()); 262 } 263 // Otherwise the enum members are accessed from the enclosing class. 264 if (parent != NULL) { 265 return ClassName(params, parent); 266 } else { 267 return ClassName(params, descriptor->file()); 268 } 269 } 270 271 string FieldConstantName(const FieldDescriptor *field) { 272 string name = field->name() + "_FIELD_NUMBER"; 273 UpperString(&name); 274 return name; 275 } 276 277 string FieldDefaultConstantName(const FieldDescriptor *field) { 278 return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default"; 279 } 280 281 void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { 282 // We don't want to print group bodies so we cut off after the first line 283 // (the second line for extensions). 284 string def = field->DebugString(); 285 string::size_type first_line_end = def.find_first_of('\n'); 286 printer->Print("// $def$\n", 287 "def", def.substr(0, first_line_end)); 288 if (field->is_extension()) { 289 string::size_type second_line_start = first_line_end + 1; 290 string::size_type second_line_length = 291 def.find('\n', second_line_start) - second_line_start; 292 printer->Print("// $def$\n", 293 "def", def.substr(second_line_start, second_line_length)); 294 } 295 } 296 297 JavaType GetJavaType(FieldDescriptor::Type field_type) { 298 switch (field_type) { 299 case FieldDescriptor::TYPE_INT32: 300 case FieldDescriptor::TYPE_UINT32: 301 case FieldDescriptor::TYPE_SINT32: 302 case FieldDescriptor::TYPE_FIXED32: 303 case FieldDescriptor::TYPE_SFIXED32: 304 return JAVATYPE_INT; 305 306 case FieldDescriptor::TYPE_INT64: 307 case FieldDescriptor::TYPE_UINT64: 308 case FieldDescriptor::TYPE_SINT64: 309 case FieldDescriptor::TYPE_FIXED64: 310 case FieldDescriptor::TYPE_SFIXED64: 311 return JAVATYPE_LONG; 312 313 case FieldDescriptor::TYPE_FLOAT: 314 return JAVATYPE_FLOAT; 315 316 case FieldDescriptor::TYPE_DOUBLE: 317 return JAVATYPE_DOUBLE; 318 319 case FieldDescriptor::TYPE_BOOL: 320 return JAVATYPE_BOOLEAN; 321 322 case FieldDescriptor::TYPE_STRING: 323 return JAVATYPE_STRING; 324 325 case FieldDescriptor::TYPE_BYTES: 326 return JAVATYPE_BYTES; 327 328 case FieldDescriptor::TYPE_ENUM: 329 return JAVATYPE_ENUM; 330 331 case FieldDescriptor::TYPE_GROUP: 332 case FieldDescriptor::TYPE_MESSAGE: 333 return JAVATYPE_MESSAGE; 334 335 // No default because we want the compiler to complain if any new 336 // types are added. 337 } 338 339 GOOGLE_LOG(FATAL) << "Can't get here."; 340 return JAVATYPE_INT; 341 } 342 343 string PrimitiveTypeName(JavaType type) { 344 switch (type) { 345 case JAVATYPE_INT : return "int"; 346 case JAVATYPE_LONG : return "long"; 347 case JAVATYPE_FLOAT : return "float"; 348 case JAVATYPE_DOUBLE : return "double"; 349 case JAVATYPE_BOOLEAN: return "boolean"; 350 case JAVATYPE_STRING : return "java.lang.String"; 351 case JAVATYPE_BYTES : return "byte[]"; 352 case JAVATYPE_ENUM : return "int"; 353 case JAVATYPE_MESSAGE: return ""; 354 355 // No default because we want the compiler to complain if any new 356 // JavaTypes are added. 357 } 358 359 GOOGLE_LOG(FATAL) << "Can't get here."; 360 return ""; 361 } 362 363 string BoxedPrimitiveTypeName(JavaType type) { 364 switch (type) { 365 case JAVATYPE_INT : return "java.lang.Integer"; 366 case JAVATYPE_LONG : return "java.lang.Long"; 367 case JAVATYPE_FLOAT : return "java.lang.Float"; 368 case JAVATYPE_DOUBLE : return "java.lang.Double"; 369 case JAVATYPE_BOOLEAN: return "java.lang.Boolean"; 370 case JAVATYPE_STRING : return "java.lang.String"; 371 case JAVATYPE_BYTES : return "byte[]"; 372 case JAVATYPE_ENUM : return "java.lang.Integer"; 373 case JAVATYPE_MESSAGE: return ""; 374 375 // No default because we want the compiler to complain if any new 376 // JavaTypes are added. 377 } 378 379 GOOGLE_LOG(FATAL) << "Can't get here."; 380 return ""; 381 } 382 383 string EmptyArrayName(const Params& params, const FieldDescriptor* field) { 384 switch (GetJavaType(field)) { 385 case JAVATYPE_INT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; 386 case JAVATYPE_LONG : return "com.google.protobuf.nano.WireFormatNano.EMPTY_LONG_ARRAY"; 387 case JAVATYPE_FLOAT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_FLOAT_ARRAY"; 388 case JAVATYPE_DOUBLE : return "com.google.protobuf.nano.WireFormatNano.EMPTY_DOUBLE_ARRAY"; 389 case JAVATYPE_BOOLEAN: return "com.google.protobuf.nano.WireFormatNano.EMPTY_BOOLEAN_ARRAY"; 390 case JAVATYPE_STRING : return "com.google.protobuf.nano.WireFormatNano.EMPTY_STRING_ARRAY"; 391 case JAVATYPE_BYTES : return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES_ARRAY"; 392 case JAVATYPE_ENUM : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; 393 case JAVATYPE_MESSAGE: return ClassName(params, field->message_type()) + ".EMPTY_ARRAY"; 394 395 // No default because we want the compiler to complain if any new 396 // JavaTypes are added. 397 } 398 399 GOOGLE_LOG(FATAL) << "Can't get here."; 400 return ""; 401 } 402 403 string DefaultValue(const Params& params, const FieldDescriptor* field) { 404 if (field->label() == FieldDescriptor::LABEL_REPEATED) { 405 return EmptyArrayName(params, field); 406 } 407 408 if (params.use_reference_types_for_primitives()) { 409 if (params.reftypes_primitive_enums() 410 && field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { 411 return "Integer.MIN_VALUE"; 412 } 413 return "null"; 414 } 415 416 // Switch on cpp_type since we need to know which default_value_* method 417 // of FieldDescriptor to call. 418 switch (field->cpp_type()) { 419 case FieldDescriptor::CPPTYPE_INT32: 420 return SimpleItoa(field->default_value_int32()); 421 case FieldDescriptor::CPPTYPE_UINT32: 422 // Need to print as a signed int since Java has no unsigned. 423 return SimpleItoa(static_cast<int32>(field->default_value_uint32())); 424 case FieldDescriptor::CPPTYPE_INT64: 425 return SimpleItoa(field->default_value_int64()) + "L"; 426 case FieldDescriptor::CPPTYPE_UINT64: 427 return SimpleItoa(static_cast<int64>(field->default_value_uint64())) + 428 "L"; 429 case FieldDescriptor::CPPTYPE_DOUBLE: { 430 double value = field->default_value_double(); 431 if (value == numeric_limits<double>::infinity()) { 432 return "Double.POSITIVE_INFINITY"; 433 } else if (value == -numeric_limits<double>::infinity()) { 434 return "Double.NEGATIVE_INFINITY"; 435 } else if (value != value) { 436 return "Double.NaN"; 437 } else { 438 return SimpleDtoa(value) + "D"; 439 } 440 } 441 case FieldDescriptor::CPPTYPE_FLOAT: { 442 float value = field->default_value_float(); 443 if (value == numeric_limits<float>::infinity()) { 444 return "Float.POSITIVE_INFINITY"; 445 } else if (value == -numeric_limits<float>::infinity()) { 446 return "Float.NEGATIVE_INFINITY"; 447 } else if (value != value) { 448 return "Float.NaN"; 449 } else { 450 return SimpleFtoa(value) + "F"; 451 } 452 } 453 case FieldDescriptor::CPPTYPE_BOOL: 454 return field->default_value_bool() ? "true" : "false"; 455 case FieldDescriptor::CPPTYPE_STRING: 456 if (!field->default_value_string().empty()) { 457 // Point it to the static final in the generated code. 458 return FieldDefaultConstantName(field); 459 } else { 460 if (field->type() == FieldDescriptor::TYPE_BYTES) { 461 return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES"; 462 } else { 463 return "\"\""; 464 } 465 } 466 467 case FieldDescriptor::CPPTYPE_ENUM: 468 return ClassName(params, field->enum_type()) + "." + 469 RenameJavaKeywords(field->default_value_enum()->name()); 470 471 case FieldDescriptor::CPPTYPE_MESSAGE: 472 return "null"; 473 474 // No default because we want the compiler to complain if any new 475 // types are added. 476 } 477 478 GOOGLE_LOG(FATAL) << "Can't get here."; 479 return ""; 480 } 481 482 483 static const char* kBitMasks[] = { 484 "0x00000001", 485 "0x00000002", 486 "0x00000004", 487 "0x00000008", 488 "0x00000010", 489 "0x00000020", 490 "0x00000040", 491 "0x00000080", 492 493 "0x00000100", 494 "0x00000200", 495 "0x00000400", 496 "0x00000800", 497 "0x00001000", 498 "0x00002000", 499 "0x00004000", 500 "0x00008000", 501 502 "0x00010000", 503 "0x00020000", 504 "0x00040000", 505 "0x00080000", 506 "0x00100000", 507 "0x00200000", 508 "0x00400000", 509 "0x00800000", 510 511 "0x01000000", 512 "0x02000000", 513 "0x04000000", 514 "0x08000000", 515 "0x10000000", 516 "0x20000000", 517 "0x40000000", 518 "0x80000000", 519 }; 520 521 string GetBitFieldName(int index) { 522 string var_name = "bitField"; 523 var_name += SimpleItoa(index); 524 var_name += "_"; 525 return var_name; 526 } 527 528 string GetBitFieldNameForBit(int bit_index) { 529 return GetBitFieldName(bit_index / 32); 530 } 531 532 string GenerateGetBit(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 + " & " + mask + ") != 0)"; 538 return result; 539 } 540 541 string GenerateSetBit(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 return result; 548 } 549 550 string GenerateClearBit(int bit_index) { 551 string var_name = GetBitFieldNameForBit(bit_index); 552 int bit_in_var_index = bit_index % 32; 553 554 string mask = kBitMasks[bit_in_var_index]; 555 string result = var_name + " = (" + var_name + " & ~" + mask + ")"; 556 return result; 557 } 558 559 string GenerateDifferentBit(int bit_index) { 560 string var_name = GetBitFieldNameForBit(bit_index); 561 int bit_in_var_index = bit_index % 32; 562 563 string mask = kBitMasks[bit_in_var_index]; 564 string result = "((" + var_name + " & " + mask 565 + ") != (other." + var_name + " & " + mask + "))"; 566 return result; 567 } 568 569 void SetBitOperationVariables(const string name, 570 int bitIndex, map<string, string>* variables) { 571 (*variables)["get_" + name] = GenerateGetBit(bitIndex); 572 (*variables)["set_" + name] = GenerateSetBit(bitIndex); 573 (*variables)["clear_" + name] = GenerateClearBit(bitIndex); 574 (*variables)["different_" + name] = GenerateDifferentBit(bitIndex); 575 } 576 577 bool HasMapField(const Descriptor* descriptor) { 578 for (int i = 0; i < descriptor->field_count(); ++i) { 579 const FieldDescriptor* field = descriptor->field(i); 580 if (field->type() == FieldDescriptor::TYPE_MESSAGE && 581 IsMapEntry(field->message_type())) { 582 return true; 583 } 584 } 585 return false; 586 } 587 588 } // namespace javanano 589 } // namespace compiler 590 } // namespace protobuf 591 } // namespace google 592