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/java/java_helpers.h>
39#include <google/protobuf/descriptor.pb.h>
40#include <google/protobuf/stubs/strutil.h>
41#include <google/protobuf/stubs/substitute.h>
42
43namespace google {
44namespace protobuf {
45namespace compiler {
46namespace java {
47
48const char kThickSeparator[] =
49  "// ===================================================================\n";
50const char kThinSeparator[] =
51  "// -------------------------------------------------------------------\n";
52
53namespace {
54
55const char* kDefaultPackage = "";
56
57const string& FieldName(const FieldDescriptor* field) {
58  // Groups are hacky:  The name of the field is just the lower-cased name
59  // of the group type.  In Java, though, we would like to retain the original
60  // capitalization of the type name.
61  if (GetType(field) == FieldDescriptor::TYPE_GROUP) {
62    return field->message_type()->name();
63  } else {
64    return field->name();
65  }
66}
67
68string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) {
69  string result;
70  // Note:  I distrust ctype.h due to locales.
71  for (int i = 0; i < input.size(); i++) {
72    if ('a' <= input[i] && input[i] <= 'z') {
73      if (cap_next_letter) {
74        result += input[i] + ('A' - 'a');
75      } else {
76        result += input[i];
77      }
78      cap_next_letter = false;
79    } else if ('A' <= input[i] && input[i] <= 'Z') {
80      if (i == 0 && !cap_next_letter) {
81        // Force first letter to lower-case unless explicitly told to
82        // capitalize it.
83        result += input[i] + ('a' - 'A');
84      } else {
85        // Capital letters after the first are left as-is.
86        result += input[i];
87      }
88      cap_next_letter = false;
89    } else if ('0' <= input[i] && input[i] <= '9') {
90      result += input[i];
91      cap_next_letter = true;
92    } else {
93      cap_next_letter = true;
94    }
95  }
96  return result;
97}
98
99}  // namespace
100
101string UnderscoresToCamelCase(const FieldDescriptor* field) {
102  return UnderscoresToCamelCaseImpl(FieldName(field), false);
103}
104
105string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
106  return UnderscoresToCamelCaseImpl(FieldName(field), true);
107}
108
109string UnderscoresToCamelCase(const MethodDescriptor* method) {
110  return UnderscoresToCamelCaseImpl(method->name(), false);
111}
112
113string StripProto(const string& filename) {
114  if (HasSuffixString(filename, ".protodevel")) {
115    return StripSuffixString(filename, ".protodevel");
116  } else {
117    return StripSuffixString(filename, ".proto");
118  }
119}
120
121string FileClassName(const FileDescriptor* file) {
122  if (file->options().has_java_outer_classname()) {
123    return file->options().java_outer_classname();
124  } else {
125    string basename;
126    string::size_type last_slash = file->name().find_last_of('/');
127    if (last_slash == string::npos) {
128      basename = file->name();
129    } else {
130      basename = file->name().substr(last_slash + 1);
131    }
132    return UnderscoresToCamelCaseImpl(StripProto(basename), true);
133  }
134}
135
136string FileJavaPackage(const FileDescriptor* file) {
137  string result;
138
139  if (file->options().has_java_package()) {
140    result = file->options().java_package();
141  } else {
142    result = kDefaultPackage;
143    if (!file->package().empty()) {
144      if (!result.empty()) result += '.';
145      result += file->package();
146    }
147  }
148
149
150  return result;
151}
152
153string JavaPackageToDir(string package_name) {
154  string package_dir =
155    StringReplace(package_name, ".", "/", true);
156  if (!package_dir.empty()) package_dir += "/";
157  return package_dir;
158}
159
160string ToJavaName(const string& full_name, const FileDescriptor* file) {
161  string result;
162  if (file->options().java_multiple_files()) {
163    result = FileJavaPackage(file);
164  } else {
165    result = ClassName(file);
166  }
167  if (!result.empty()) {
168    result += '.';
169  }
170  if (file->package().empty()) {
171    result += full_name;
172  } else {
173    // Strip the proto package from full_name since we've replaced it with
174    // the Java package.
175    result += full_name.substr(file->package().size() + 1);
176  }
177  return result;
178}
179
180string ClassName(const Descriptor* descriptor) {
181  return ToJavaName(descriptor->full_name(), descriptor->file());
182}
183
184string ClassName(const EnumDescriptor* descriptor) {
185  return ToJavaName(descriptor->full_name(), descriptor->file());
186}
187
188string ClassName(const ServiceDescriptor* descriptor) {
189  return ToJavaName(descriptor->full_name(), descriptor->file());
190}
191
192string ClassName(const FileDescriptor* descriptor) {
193  string result = FileJavaPackage(descriptor);
194  if (!result.empty()) result += '.';
195  result += FileClassName(descriptor);
196  return result;
197}
198
199string FieldConstantName(const FieldDescriptor *field) {
200  string name = field->name() + "_FIELD_NUMBER";
201  UpperString(&name);
202  return name;
203}
204
205FieldDescriptor::Type GetType(const FieldDescriptor* field) {
206  return field->type();
207}
208
209JavaType GetJavaType(const FieldDescriptor* field) {
210  switch (GetType(field)) {
211    case FieldDescriptor::TYPE_INT32:
212    case FieldDescriptor::TYPE_UINT32:
213    case FieldDescriptor::TYPE_SINT32:
214    case FieldDescriptor::TYPE_FIXED32:
215    case FieldDescriptor::TYPE_SFIXED32:
216      return JAVATYPE_INT;
217
218    case FieldDescriptor::TYPE_INT64:
219    case FieldDescriptor::TYPE_UINT64:
220    case FieldDescriptor::TYPE_SINT64:
221    case FieldDescriptor::TYPE_FIXED64:
222    case FieldDescriptor::TYPE_SFIXED64:
223      return JAVATYPE_LONG;
224
225    case FieldDescriptor::TYPE_FLOAT:
226      return JAVATYPE_FLOAT;
227
228    case FieldDescriptor::TYPE_DOUBLE:
229      return JAVATYPE_DOUBLE;
230
231    case FieldDescriptor::TYPE_BOOL:
232      return JAVATYPE_BOOLEAN;
233
234    case FieldDescriptor::TYPE_STRING:
235      return JAVATYPE_STRING;
236
237    case FieldDescriptor::TYPE_BYTES:
238      return JAVATYPE_BYTES;
239
240    case FieldDescriptor::TYPE_ENUM:
241      return JAVATYPE_ENUM;
242
243    case FieldDescriptor::TYPE_GROUP:
244    case FieldDescriptor::TYPE_MESSAGE:
245      return JAVATYPE_MESSAGE;
246
247    // No default because we want the compiler to complain if any new
248    // types are added.
249  }
250
251  GOOGLE_LOG(FATAL) << "Can't get here.";
252  return JAVATYPE_INT;
253}
254
255const char* BoxedPrimitiveTypeName(JavaType type) {
256  switch (type) {
257    case JAVATYPE_INT    : return "java.lang.Integer";
258    case JAVATYPE_LONG   : return "java.lang.Long";
259    case JAVATYPE_FLOAT  : return "java.lang.Float";
260    case JAVATYPE_DOUBLE : return "java.lang.Double";
261    case JAVATYPE_BOOLEAN: return "java.lang.Boolean";
262    case JAVATYPE_STRING : return "java.lang.String";
263    case JAVATYPE_BYTES  : return "com.google.protobuf.ByteString";
264    case JAVATYPE_ENUM   : return NULL;
265    case JAVATYPE_MESSAGE: return NULL;
266
267    // No default because we want the compiler to complain if any new
268    // JavaTypes are added.
269  }
270
271  GOOGLE_LOG(FATAL) << "Can't get here.";
272  return NULL;
273}
274
275bool AllAscii(const string& text) {
276  for (int i = 0; i < text.size(); i++) {
277    if ((text[i] & 0x80) != 0) {
278      return false;
279    }
280  }
281  return true;
282}
283
284string DefaultValue(const FieldDescriptor* field) {
285  // Switch on CppType since we need to know which default_value_* method
286  // of FieldDescriptor to call.
287  switch (field->cpp_type()) {
288    case FieldDescriptor::CPPTYPE_INT32:
289      return SimpleItoa(field->default_value_int32());
290    case FieldDescriptor::CPPTYPE_UINT32:
291      // Need to print as a signed int since Java has no unsigned.
292      return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
293    case FieldDescriptor::CPPTYPE_INT64:
294      return SimpleItoa(field->default_value_int64()) + "L";
295    case FieldDescriptor::CPPTYPE_UINT64:
296      return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
297             "L";
298    case FieldDescriptor::CPPTYPE_DOUBLE: {
299      double value = field->default_value_double();
300      if (value == numeric_limits<double>::infinity()) {
301        return "Double.POSITIVE_INFINITY";
302      } else if (value == -numeric_limits<double>::infinity()) {
303        return "Double.NEGATIVE_INFINITY";
304      } else if (value != value) {
305        return "Double.NaN";
306      } else {
307        return SimpleDtoa(value) + "D";
308      }
309    }
310    case FieldDescriptor::CPPTYPE_FLOAT: {
311      float value = field->default_value_float();
312      if (value == numeric_limits<float>::infinity()) {
313        return "Float.POSITIVE_INFINITY";
314      } else if (value == -numeric_limits<float>::infinity()) {
315        return "Float.NEGATIVE_INFINITY";
316      } else if (value != value) {
317        return "Float.NaN";
318      } else {
319        return SimpleFtoa(value) + "F";
320      }
321    }
322    case FieldDescriptor::CPPTYPE_BOOL:
323      return field->default_value_bool() ? "true" : "false";
324    case FieldDescriptor::CPPTYPE_STRING:
325      if (GetType(field) == FieldDescriptor::TYPE_BYTES) {
326        if (field->has_default_value()) {
327          // See comments in Internal.java for gory details.
328          return strings::Substitute(
329            "com.google.protobuf.Internal.bytesDefaultValue(\"$0\")",
330            CEscape(field->default_value_string()));
331        } else {
332          return "com.google.protobuf.ByteString.EMPTY";
333        }
334      } else {
335        if (AllAscii(field->default_value_string())) {
336          // All chars are ASCII.  In this case CEscape() works fine.
337          return "\"" + CEscape(field->default_value_string()) + "\"";
338        } else {
339          // See comments in Internal.java for gory details.
340          return strings::Substitute(
341              "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
342              CEscape(field->default_value_string()));
343        }
344      }
345
346    case FieldDescriptor::CPPTYPE_ENUM:
347      return ClassName(field->enum_type()) + "." +
348          field->default_value_enum()->name();
349
350    case FieldDescriptor::CPPTYPE_MESSAGE:
351      return ClassName(field->message_type()) + ".getDefaultInstance()";
352
353    // No default because we want the compiler to complain if any new
354    // types are added.
355  }
356
357  GOOGLE_LOG(FATAL) << "Can't get here.";
358  return "";
359}
360
361bool IsDefaultValueJavaDefault(const FieldDescriptor* field) {
362  // Switch on CppType since we need to know which default_value_* method
363  // of FieldDescriptor to call.
364  switch (field->cpp_type()) {
365    case FieldDescriptor::CPPTYPE_INT32:
366      return field->default_value_int32() == 0;
367    case FieldDescriptor::CPPTYPE_UINT32:
368      return field->default_value_uint32() == 0;
369    case FieldDescriptor::CPPTYPE_INT64:
370      return field->default_value_int64() == 0L;
371    case FieldDescriptor::CPPTYPE_UINT64:
372      return field->default_value_uint64() == 0L;
373    case FieldDescriptor::CPPTYPE_DOUBLE:
374      return field->default_value_double() == 0.0;
375    case FieldDescriptor::CPPTYPE_FLOAT:
376      return field->default_value_float() == 0.0;
377    case FieldDescriptor::CPPTYPE_BOOL:
378      return field->default_value_bool() == false;
379
380    case FieldDescriptor::CPPTYPE_STRING:
381    case FieldDescriptor::CPPTYPE_ENUM:
382    case FieldDescriptor::CPPTYPE_MESSAGE:
383      return false;
384
385    // No default because we want the compiler to complain if any new
386    // types are added.
387  }
388
389  GOOGLE_LOG(FATAL) << "Can't get here.";
390  return false;
391}
392
393const char* bit_masks[] = {
394  "0x00000001",
395  "0x00000002",
396  "0x00000004",
397  "0x00000008",
398  "0x00000010",
399  "0x00000020",
400  "0x00000040",
401  "0x00000080",
402
403  "0x00000100",
404  "0x00000200",
405  "0x00000400",
406  "0x00000800",
407  "0x00001000",
408  "0x00002000",
409  "0x00004000",
410  "0x00008000",
411
412  "0x00010000",
413  "0x00020000",
414  "0x00040000",
415  "0x00080000",
416  "0x00100000",
417  "0x00200000",
418  "0x00400000",
419  "0x00800000",
420
421  "0x01000000",
422  "0x02000000",
423  "0x04000000",
424  "0x08000000",
425  "0x10000000",
426  "0x20000000",
427  "0x40000000",
428  "0x80000000",
429};
430
431string GetBitFieldName(int index) {
432  string varName = "bitField";
433  varName += SimpleItoa(index);
434  varName += "_";
435  return varName;
436}
437
438string GetBitFieldNameForBit(int bitIndex) {
439  return GetBitFieldName(bitIndex / 32);
440}
441
442namespace {
443
444string GenerateGetBitInternal(const string& prefix, int bitIndex) {
445  string varName = prefix + GetBitFieldNameForBit(bitIndex);
446  int bitInVarIndex = bitIndex % 32;
447
448  string mask = bit_masks[bitInVarIndex];
449  string result = "((" + varName + " & " + mask + ") == " + mask + ")";
450  return result;
451}
452
453string GenerateSetBitInternal(const string& prefix, int bitIndex) {
454  string varName = prefix + GetBitFieldNameForBit(bitIndex);
455  int bitInVarIndex = bitIndex % 32;
456
457  string mask = bit_masks[bitInVarIndex];
458  string result = varName + " |= " + mask;
459  return result;
460}
461
462}  // namespace
463
464string GenerateGetBit(int bitIndex) {
465  return GenerateGetBitInternal("", bitIndex);
466}
467
468string GenerateSetBit(int bitIndex) {
469  return GenerateSetBitInternal("", bitIndex);
470}
471
472string GenerateClearBit(int bitIndex) {
473  string varName = GetBitFieldNameForBit(bitIndex);
474  int bitInVarIndex = bitIndex % 32;
475
476  string mask = bit_masks[bitInVarIndex];
477  string result = varName + " = (" + varName + " & ~" + mask + ")";
478  return result;
479}
480
481string GenerateGetBitFromLocal(int bitIndex) {
482  return GenerateGetBitInternal("from_", bitIndex);
483}
484
485string GenerateSetBitToLocal(int bitIndex) {
486  return GenerateSetBitInternal("to_", bitIndex);
487}
488
489string GenerateGetBitMutableLocal(int bitIndex) {
490  return GenerateGetBitInternal("mutable_", bitIndex);
491}
492
493string GenerateSetBitMutableLocal(int bitIndex) {
494  return GenerateSetBitInternal("mutable_", bitIndex);
495}
496
497}  // namespace java
498}  // namespace compiler
499}  // namespace protobuf
500}  // namespace google
501