blob: 1b6f1653107147bd8d477bc9159a63c1ec6270ae [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001// Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002// Copyright 2008 Google Inc. All rights reserved.
temporal40ee5512008-07-10 02:12:20 +00003// http://code.google.com/p/protobuf/
4//
kenton@google.com24bf56f2008-09-24 20:31:01 +00005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
temporal40ee5512008-07-10 02:12:20 +00008//
kenton@google.com24bf56f2008-09-24 20:31:01 +00009// * 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.
temporal40ee5512008-07-10 02:12:20 +000018//
kenton@google.com24bf56f2008-09-24 20:31:01 +000019// 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.
temporal40ee5512008-07-10 02:12:20 +000030
31// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34
kenton@google.comfccb1462009-12-18 02:11:36 +000035#include <limits>
temporal40ee5512008-07-10 02:12:20 +000036#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>
kenton@google.com80b1d622009-07-29 01:13:20 +000041#include <google/protobuf/stubs/substitute.h>
temporal40ee5512008-07-10 02:12:20 +000042
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.
kenton@google.comfccb1462009-12-18 02:11:36 +000061 if (GetType(field) == FieldDescriptor::TYPE_GROUP) {
temporal40ee5512008-07-10 02:12:20 +000062 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) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000137 string result;
138
temporal40ee5512008-07-10 02:12:20 +0000139 if (file->options().has_java_package()) {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000140 result = file->options().java_package();
temporal40ee5512008-07-10 02:12:20 +0000141 } else {
liujisi@google.com33165fe2010-11-02 13:14:58 +0000142 result = kDefaultPackage;
temporal40ee5512008-07-10 02:12:20 +0000143 if (!file->package().empty()) {
144 if (!result.empty()) result += '.';
145 result += file->package();
146 }
temporal40ee5512008-07-10 02:12:20 +0000147 }
liujisi@google.com33165fe2010-11-02 13:14:58 +0000148
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;
temporal40ee5512008-07-10 02:12:20 +0000158}
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 FileDescriptor* descriptor) {
181 string result = FileJavaPackage(descriptor);
182 if (!result.empty()) result += '.';
183 result += FileClassName(descriptor);
184 return result;
185}
186
kenton@google.comcfa2d8a2009-04-18 00:02:12 +0000187string FieldConstantName(const FieldDescriptor *field) {
188 string name = field->name() + "_FIELD_NUMBER";
189 UpperString(&name);
190 return name;
191}
192
kenton@google.comfccb1462009-12-18 02:11:36 +0000193FieldDescriptor::Type GetType(const FieldDescriptor* field) {
194 return field->type();
195}
196
197JavaType GetJavaType(const FieldDescriptor* field) {
198 switch (GetType(field)) {
temporal40ee5512008-07-10 02:12:20 +0000199 case FieldDescriptor::TYPE_INT32:
200 case FieldDescriptor::TYPE_UINT32:
201 case FieldDescriptor::TYPE_SINT32:
202 case FieldDescriptor::TYPE_FIXED32:
203 case FieldDescriptor::TYPE_SFIXED32:
204 return JAVATYPE_INT;
205
206 case FieldDescriptor::TYPE_INT64:
207 case FieldDescriptor::TYPE_UINT64:
208 case FieldDescriptor::TYPE_SINT64:
209 case FieldDescriptor::TYPE_FIXED64:
210 case FieldDescriptor::TYPE_SFIXED64:
211 return JAVATYPE_LONG;
212
213 case FieldDescriptor::TYPE_FLOAT:
214 return JAVATYPE_FLOAT;
215
216 case FieldDescriptor::TYPE_DOUBLE:
217 return JAVATYPE_DOUBLE;
218
219 case FieldDescriptor::TYPE_BOOL:
220 return JAVATYPE_BOOLEAN;
221
222 case FieldDescriptor::TYPE_STRING:
223 return JAVATYPE_STRING;
224
225 case FieldDescriptor::TYPE_BYTES:
226 return JAVATYPE_BYTES;
227
228 case FieldDescriptor::TYPE_ENUM:
229 return JAVATYPE_ENUM;
230
231 case FieldDescriptor::TYPE_GROUP:
232 case FieldDescriptor::TYPE_MESSAGE:
233 return JAVATYPE_MESSAGE;
234
235 // No default because we want the compiler to complain if any new
236 // types are added.
237 }
238
239 GOOGLE_LOG(FATAL) << "Can't get here.";
240 return JAVATYPE_INT;
241}
242
243const char* BoxedPrimitiveTypeName(JavaType type) {
244 switch (type) {
245 case JAVATYPE_INT : return "java.lang.Integer";
246 case JAVATYPE_LONG : return "java.lang.Long";
247 case JAVATYPE_FLOAT : return "java.lang.Float";
248 case JAVATYPE_DOUBLE : return "java.lang.Double";
249 case JAVATYPE_BOOLEAN: return "java.lang.Boolean";
250 case JAVATYPE_STRING : return "java.lang.String";
251 case JAVATYPE_BYTES : return "com.google.protobuf.ByteString";
252 case JAVATYPE_ENUM : return NULL;
253 case JAVATYPE_MESSAGE: return NULL;
254
255 // No default because we want the compiler to complain if any new
256 // JavaTypes are added.
257 }
258
259 GOOGLE_LOG(FATAL) << "Can't get here.";
260 return NULL;
261}
262
kenton@google.com80b1d622009-07-29 01:13:20 +0000263bool AllAscii(const string& text) {
264 for (int i = 0; i < text.size(); i++) {
265 if ((text[i] & 0x80) != 0) {
266 return false;
267 }
268 }
269 return true;
270}
271
272string DefaultValue(const FieldDescriptor* field) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000273 // Switch on CppType since we need to know which default_value_* method
kenton@google.com80b1d622009-07-29 01:13:20 +0000274 // of FieldDescriptor to call.
275 switch (field->cpp_type()) {
276 case FieldDescriptor::CPPTYPE_INT32:
277 return SimpleItoa(field->default_value_int32());
278 case FieldDescriptor::CPPTYPE_UINT32:
279 // Need to print as a signed int since Java has no unsigned.
280 return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
281 case FieldDescriptor::CPPTYPE_INT64:
282 return SimpleItoa(field->default_value_int64()) + "L";
283 case FieldDescriptor::CPPTYPE_UINT64:
284 return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
285 "L";
kenton@google.comfccb1462009-12-18 02:11:36 +0000286 case FieldDescriptor::CPPTYPE_DOUBLE: {
287 double value = field->default_value_double();
288 if (value == numeric_limits<double>::infinity()) {
289 return "Double.POSITIVE_INFINITY";
290 } else if (value == -numeric_limits<double>::infinity()) {
291 return "Double.NEGATIVE_INFINITY";
292 } else if (value != value) {
293 return "Double.NaN";
294 } else {
295 return SimpleDtoa(value) + "D";
296 }
297 }
298 case FieldDescriptor::CPPTYPE_FLOAT: {
299 float value = field->default_value_float();
300 if (value == numeric_limits<float>::infinity()) {
301 return "Float.POSITIVE_INFINITY";
302 } else if (value == -numeric_limits<float>::infinity()) {
303 return "Float.NEGATIVE_INFINITY";
304 } else if (value != value) {
305 return "Float.NaN";
306 } else {
307 return SimpleFtoa(value) + "F";
308 }
309 }
kenton@google.com80b1d622009-07-29 01:13:20 +0000310 case FieldDescriptor::CPPTYPE_BOOL:
311 return field->default_value_bool() ? "true" : "false";
312 case FieldDescriptor::CPPTYPE_STRING:
kenton@google.comfccb1462009-12-18 02:11:36 +0000313 if (GetType(field) == FieldDescriptor::TYPE_BYTES) {
kenton@google.com80b1d622009-07-29 01:13:20 +0000314 if (field->has_default_value()) {
315 // See comments in Internal.java for gory details.
316 return strings::Substitute(
317 "com.google.protobuf.Internal.bytesDefaultValue(\"$0\")",
318 CEscape(field->default_value_string()));
319 } else {
320 return "com.google.protobuf.ByteString.EMPTY";
321 }
322 } else {
323 if (AllAscii(field->default_value_string())) {
324 // All chars are ASCII. In this case CEscape() works fine.
325 return "\"" + CEscape(field->default_value_string()) + "\"";
326 } else {
327 // See comments in Internal.java for gory details.
328 return strings::Substitute(
329 "com.google.protobuf.Internal.stringDefaultValue(\"$0\")",
330 CEscape(field->default_value_string()));
331 }
332 }
333
334 case FieldDescriptor::CPPTYPE_ENUM:
335 return ClassName(field->enum_type()) + "." +
336 field->default_value_enum()->name();
337
338 case FieldDescriptor::CPPTYPE_MESSAGE:
339 return ClassName(field->message_type()) + ".getDefaultInstance()";
340
341 // No default because we want the compiler to complain if any new
342 // types are added.
343 }
344
345 GOOGLE_LOG(FATAL) << "Can't get here.";
346 return "";
347}
348
liujisi@google.com33165fe2010-11-02 13:14:58 +0000349bool IsDefaultValueJavaDefault(const FieldDescriptor* field) {
350 // Switch on CppType since we need to know which default_value_* method
351 // of FieldDescriptor to call.
352 switch (field->cpp_type()) {
353 case FieldDescriptor::CPPTYPE_INT32:
354 return field->default_value_int32() == 0;
355 case FieldDescriptor::CPPTYPE_UINT32:
356 return field->default_value_uint32() == 0;
357 case FieldDescriptor::CPPTYPE_INT64:
358 return field->default_value_int64() == 0L;
359 case FieldDescriptor::CPPTYPE_UINT64:
360 return field->default_value_uint64() == 0L;
361 case FieldDescriptor::CPPTYPE_DOUBLE:
362 return field->default_value_double() == 0.0;
363 case FieldDescriptor::CPPTYPE_FLOAT:
364 return field->default_value_float() == 0.0;
365 case FieldDescriptor::CPPTYPE_BOOL:
366 return field->default_value_bool() == false;
367
368 case FieldDescriptor::CPPTYPE_STRING:
369 case FieldDescriptor::CPPTYPE_ENUM:
370 case FieldDescriptor::CPPTYPE_MESSAGE:
371 return false;
372
373 // No default because we want the compiler to complain if any new
374 // types are added.
375 }
376
377 GOOGLE_LOG(FATAL) << "Can't get here.";
378 return false;
379}
380
381const char* bit_masks[] = {
382 "0x00000001",
383 "0x00000002",
384 "0x00000004",
385 "0x00000008",
386 "0x00000010",
387 "0x00000020",
388 "0x00000040",
389 "0x00000080",
390
391 "0x00000100",
392 "0x00000200",
393 "0x00000400",
394 "0x00000800",
395 "0x00001000",
396 "0x00002000",
397 "0x00004000",
398 "0x00008000",
399
400 "0x00010000",
401 "0x00020000",
402 "0x00040000",
403 "0x00080000",
404 "0x00100000",
405 "0x00200000",
406 "0x00400000",
407 "0x00800000",
408
409 "0x01000000",
410 "0x02000000",
411 "0x04000000",
412 "0x08000000",
413 "0x10000000",
414 "0x20000000",
415 "0x40000000",
416 "0x80000000",
417};
418
419string GetBitFieldName(int index) {
420 string varName = "bitField";
421 varName += SimpleItoa(index);
422 varName += "_";
423 return varName;
424}
425
426string GetBitFieldNameForBit(int bitIndex) {
427 return GetBitFieldName(bitIndex / 32);
428}
429
430string GenerateGetBit(int bitIndex) {
431 string varName = GetBitFieldNameForBit(bitIndex);
432 int bitInVarIndex = bitIndex % 32;
433
434 string mask = bit_masks[bitInVarIndex];
435 string result = "((" + varName + " & " + mask + ") == " + mask + ")";
436 return result;
437}
438
439string GenerateSetBit(int bitIndex) {
440 string varName = GetBitFieldNameForBit(bitIndex);
441 int bitInVarIndex = bitIndex % 32;
442
443 string mask = bit_masks[bitInVarIndex];
444 string result = varName + " |= " + mask;
445 return result;
446}
447
448string GenerateClearBit(int bitIndex) {
449 string varName = GetBitFieldNameForBit(bitIndex);
450 int bitInVarIndex = bitIndex % 32;
451
452 string mask = bit_masks[bitInVarIndex];
453 string result = varName + " = (" + varName + " & ~" + mask + ")";
454 return result;
455}
456
457string GenerateGetBitFromLocal(int bitIndex) {
458 string varName = "from_" + GetBitFieldNameForBit(bitIndex);
459 int bitInVarIndex = bitIndex % 32;
460
461 string mask = bit_masks[bitInVarIndex];
462 string result = "((" + varName + " & " + mask + ") == " + mask + ")";
463 return result;
464}
465
466string GenerateSetBitToLocal(int bitIndex) {
467 string varName = "to_" + GetBitFieldNameForBit(bitIndex);
468 int bitInVarIndex = bitIndex % 32;
469
470 string mask = bit_masks[bitInVarIndex];
471 string result = varName + " |= " + mask;
472 return result;
473}
474
temporal40ee5512008-07-10 02:12:20 +0000475} // namespace java
476} // namespace compiler
477} // namespace protobuf
478} // namespace google