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@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:
RenameKeywords()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)
RenameJavaKeywordsImpl(const string & input)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 
FieldName(const FieldDescriptor * field)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 
UnderscoresToCamelCaseImpl(const string & input,bool cap_next_letter)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 
UnderscoresToCamelCase(const FieldDescriptor * field)145 string UnderscoresToCamelCase(const FieldDescriptor* field) {
146   return UnderscoresToCamelCaseImpl(FieldName(field), false);
147 }
148 
UnderscoresToCapitalizedCamelCase(const FieldDescriptor * field)149 string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
150   return UnderscoresToCamelCaseImpl(FieldName(field), true);
151 }
152 
UnderscoresToCamelCase(const MethodDescriptor * method)153 string UnderscoresToCamelCase(const MethodDescriptor* method) {
154   return UnderscoresToCamelCaseImpl(method->name(), false);
155 }
156 
RenameJavaKeywords(const string & input)157 string RenameJavaKeywords(const string& input) {
158   return sRenameKeywords.RenameJavaKeywordsImpl(input);
159 }
160 
StripProto(const string & filename)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 
FileClassName(const Params & params,const FileDescriptor * file)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 
FileJavaPackage(const Params & params,const FileDescriptor * file)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 
IsOuterClassNeeded(const Params & params,const FileDescriptor * file)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 
ToJavaName(const Params & params,const string & name,bool is_class,const Descriptor * parent,const FileDescriptor * file)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 
ClassName(const Params & params,const FileDescriptor * descriptor)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 
ClassName(const Params & params,const EnumDescriptor * descriptor)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 
FieldConstantName(const FieldDescriptor * field)257 string FieldConstantName(const FieldDescriptor *field) {
258   string name = field->name() + "_FIELD_NUMBER";
259   UpperString(&name);
260   return name;
261 }
262 
FieldDefaultConstantName(const FieldDescriptor * field)263 string FieldDefaultConstantName(const FieldDescriptor *field) {
264   return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default";
265 }
266 
PrintFieldComment(io::Printer * printer,const FieldDescriptor * field)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 
GetJavaType(FieldDescriptor::Type field_type)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 
PrimitiveTypeName(JavaType type)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 "";
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 "";
347 }
348 
BoxedPrimitiveTypeName(JavaType type)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 "";
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 "";
367 }
368 
EmptyArrayName(const Params & params,const FieldDescriptor * field)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 
DefaultValue(const Params & params,const FieldDescriptor * field)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     if (params.reftypes_primitive_enums()
396           && field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
397       return "Integer.MIN_VALUE";
398     }
399     return "null";
400   }
401 
402   // Switch on cpp_type since we need to know which default_value_* method
403   // of FieldDescriptor to call.
404   switch (field->cpp_type()) {
405     case FieldDescriptor::CPPTYPE_INT32:
406       return SimpleItoa(field->default_value_int32());
407     case FieldDescriptor::CPPTYPE_UINT32:
408       // Need to print as a signed int since Java has no unsigned.
409       return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
410     case FieldDescriptor::CPPTYPE_INT64:
411       return SimpleItoa(field->default_value_int64()) + "L";
412     case FieldDescriptor::CPPTYPE_UINT64:
413       return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
414              "L";
415     case FieldDescriptor::CPPTYPE_DOUBLE: {
416       double value = field->default_value_double();
417       if (value == numeric_limits<double>::infinity()) {
418         return "Double.POSITIVE_INFINITY";
419       } else if (value == -numeric_limits<double>::infinity()) {
420         return "Double.NEGATIVE_INFINITY";
421       } else if (value != value) {
422         return "Double.NaN";
423       } else {
424         return SimpleDtoa(value) + "D";
425       }
426     }
427     case FieldDescriptor::CPPTYPE_FLOAT: {
428       float value = field->default_value_float();
429       if (value == numeric_limits<float>::infinity()) {
430         return "Float.POSITIVE_INFINITY";
431       } else if (value == -numeric_limits<float>::infinity()) {
432         return "Float.NEGATIVE_INFINITY";
433       } else if (value != value) {
434         return "Float.NaN";
435       } else {
436         return SimpleFtoa(value) + "F";
437       }
438     }
439     case FieldDescriptor::CPPTYPE_BOOL:
440       return field->default_value_bool() ? "true" : "false";
441     case FieldDescriptor::CPPTYPE_STRING:
442       if (!field->default_value_string().empty()) {
443         // Point it to the static final in the generated code.
444         return FieldDefaultConstantName(field);
445       } else {
446         if (field->type() == FieldDescriptor::TYPE_BYTES) {
447           return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES";
448         } else {
449           return "\"\"";
450         }
451       }
452 
453     case FieldDescriptor::CPPTYPE_ENUM:
454       return ClassName(params, field->enum_type()) + "." +
455              RenameJavaKeywords(field->default_value_enum()->name());
456 
457     case FieldDescriptor::CPPTYPE_MESSAGE:
458       return "null";
459 
460     // No default because we want the compiler to complain if any new
461     // types are added.
462   }
463 
464   GOOGLE_LOG(FATAL) << "Can't get here.";
465   return "";
466 }
467 
468 
469 static const char* kBitMasks[] = {
470   "0x00000001",
471   "0x00000002",
472   "0x00000004",
473   "0x00000008",
474   "0x00000010",
475   "0x00000020",
476   "0x00000040",
477   "0x00000080",
478 
479   "0x00000100",
480   "0x00000200",
481   "0x00000400",
482   "0x00000800",
483   "0x00001000",
484   "0x00002000",
485   "0x00004000",
486   "0x00008000",
487 
488   "0x00010000",
489   "0x00020000",
490   "0x00040000",
491   "0x00080000",
492   "0x00100000",
493   "0x00200000",
494   "0x00400000",
495   "0x00800000",
496 
497   "0x01000000",
498   "0x02000000",
499   "0x04000000",
500   "0x08000000",
501   "0x10000000",
502   "0x20000000",
503   "0x40000000",
504   "0x80000000",
505 };
506 
GetBitFieldName(int index)507 string GetBitFieldName(int index) {
508   string var_name = "bitField";
509   var_name += SimpleItoa(index);
510   var_name += "_";
511   return var_name;
512 }
513 
GetBitFieldNameForBit(int bit_index)514 string GetBitFieldNameForBit(int bit_index) {
515   return GetBitFieldName(bit_index / 32);
516 }
517 
GenerateGetBit(int bit_index)518 string GenerateGetBit(int bit_index) {
519   string var_name = GetBitFieldNameForBit(bit_index);
520   int bit_in_var_index = bit_index % 32;
521 
522   string mask = kBitMasks[bit_in_var_index];
523   string result = "((" + var_name + " & " + mask + ") != 0)";
524   return result;
525 }
526 
GenerateSetBit(int bit_index)527 string GenerateSetBit(int bit_index) {
528   string var_name = GetBitFieldNameForBit(bit_index);
529   int bit_in_var_index = bit_index % 32;
530 
531   string mask = kBitMasks[bit_in_var_index];
532   string result = var_name + " |= " + mask;
533   return result;
534 }
535 
GenerateClearBit(int bit_index)536 string GenerateClearBit(int bit_index) {
537   string var_name = GetBitFieldNameForBit(bit_index);
538   int bit_in_var_index = bit_index % 32;
539 
540   string mask = kBitMasks[bit_in_var_index];
541   string result = var_name + " = (" + var_name + " & ~" + mask + ")";
542   return result;
543 }
544 
GenerateDifferentBit(int bit_index)545 string GenerateDifferentBit(int bit_index) {
546   string var_name = GetBitFieldNameForBit(bit_index);
547   int bit_in_var_index = bit_index % 32;
548 
549   string mask = kBitMasks[bit_in_var_index];
550   string result = "((" + var_name + " & " + mask
551       + ") != (other." + var_name + " & " + mask + "))";
552   return result;
553 }
554 
SetBitOperationVariables(const string name,int bitIndex,map<string,string> * variables)555 void SetBitOperationVariables(const string name,
556     int bitIndex, map<string, string>* variables) {
557   (*variables)["get_" + name] = GenerateGetBit(bitIndex);
558   (*variables)["set_" + name] = GenerateSetBit(bitIndex);
559   (*variables)["clear_" + name] = GenerateClearBit(bitIndex);
560   (*variables)["different_" + name] = GenerateDifferentBit(bitIndex);
561 }
562 
563 }  // namespace javanano
564 }  // namespace compiler
565 }  // namespace protobuf
566 }  // namespace google
567