OLD | NEW |
| (Empty) |
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 | |
43 namespace google { | |
44 namespace protobuf { | |
45 namespace compiler { | |
46 namespace java { | |
47 | |
48 const char kThickSeparator[] = | |
49 "// ===================================================================\n"; | |
50 const char kThinSeparator[] = | |
51 "// -------------------------------------------------------------------\n"; | |
52 | |
53 namespace { | |
54 | |
55 const char* kDefaultPackage = ""; | |
56 | |
57 const 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 | |
68 string 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 | |
101 string UnderscoresToCamelCase(const FieldDescriptor* field) { | |
102 return UnderscoresToCamelCaseImpl(FieldName(field), false); | |
103 } | |
104 | |
105 string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { | |
106 return UnderscoresToCamelCaseImpl(FieldName(field), true); | |
107 } | |
108 | |
109 string UnderscoresToCamelCase(const MethodDescriptor* method) { | |
110 return UnderscoresToCamelCaseImpl(method->name(), false); | |
111 } | |
112 | |
113 string StripProto(const string& filename) { | |
114 if (HasSuffixString(filename, ".protodevel")) { | |
115 return StripSuffixString(filename, ".protodevel"); | |
116 } else { | |
117 return StripSuffixString(filename, ".proto"); | |
118 } | |
119 } | |
120 | |
121 string 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 | |
136 string 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 | |
153 string 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 | |
160 string 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 | |
180 string ClassName(const Descriptor* descriptor) { | |
181 return ToJavaName(descriptor->full_name(), descriptor->file()); | |
182 } | |
183 | |
184 string ClassName(const EnumDescriptor* descriptor) { | |
185 return ToJavaName(descriptor->full_name(), descriptor->file()); | |
186 } | |
187 | |
188 string ClassName(const ServiceDescriptor* descriptor) { | |
189 return ToJavaName(descriptor->full_name(), descriptor->file()); | |
190 } | |
191 | |
192 string ClassName(const FileDescriptor* descriptor) { | |
193 string result = FileJavaPackage(descriptor); | |
194 if (!result.empty()) result += '.'; | |
195 result += FileClassName(descriptor); | |
196 return result; | |
197 } | |
198 | |
199 string FieldConstantName(const FieldDescriptor *field) { | |
200 string name = field->name() + "_FIELD_NUMBER"; | |
201 UpperString(&name); | |
202 return name; | |
203 } | |
204 | |
205 FieldDescriptor::Type GetType(const FieldDescriptor* field) { | |
206 return field->type(); | |
207 } | |
208 | |
209 JavaType 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 | |
255 const 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 | |
275 bool 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 | |
284 string 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 | |
361 bool 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 | |
393 const 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 | |
431 string GetBitFieldName(int index) { | |
432 string varName = "bitField"; | |
433 varName += SimpleItoa(index); | |
434 varName += "_"; | |
435 return varName; | |
436 } | |
437 | |
438 string GetBitFieldNameForBit(int bitIndex) { | |
439 return GetBitFieldName(bitIndex / 32); | |
440 } | |
441 | |
442 namespace { | |
443 | |
444 string 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 | |
453 string 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 | |
464 string GenerateGetBit(int bitIndex) { | |
465 return GenerateGetBitInternal("", bitIndex); | |
466 } | |
467 | |
468 string GenerateSetBit(int bitIndex) { | |
469 return GenerateSetBitInternal("", bitIndex); | |
470 } | |
471 | |
472 string 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 | |
481 string GenerateGetBitFromLocal(int bitIndex) { | |
482 return GenerateGetBitInternal("from_", bitIndex); | |
483 } | |
484 | |
485 string GenerateSetBitToLocal(int bitIndex) { | |
486 return GenerateSetBitInternal("to_", bitIndex); | |
487 } | |
488 | |
489 string GenerateGetBitMutableLocal(int bitIndex) { | |
490 return GenerateGetBitInternal("mutable_", bitIndex); | |
491 } | |
492 | |
493 string GenerateSetBitMutableLocal(int bitIndex) { | |
494 return GenerateSetBitInternal("mutable_", bitIndex); | |
495 } | |
496 | |
497 } // namespace java | |
498 } // namespace compiler | |
499 } // namespace protobuf | |
500 } // namespace google | |
OLD | NEW |