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 <algorithm>
36 #include <google/protobuf/stubs/hash.h>
37 #include <google/protobuf/compiler/javamicro/javamicro_message.h>
38 #include <google/protobuf/compiler/javamicro/javamicro_enum.h>
39 #include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
40 #include <google/protobuf/stubs/strutil.h>
41 #include <google/protobuf/io/printer.h>
42 #include <google/protobuf/io/coded_stream.h>
43 #include <google/protobuf/wire_format.h>
44 #include <google/protobuf/descriptor.pb.h>
45
46 namespace google {
47 namespace protobuf {
48 namespace compiler {
49 namespace javamicro {
50
51 using internal::WireFormat;
52 using internal::WireFormatLite;
53
54 namespace {
55
PrintFieldComment(io::Printer * printer,const FieldDescriptor * field)56 void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
57 // Print the field's proto-syntax definition as a comment. We don't want to
58 // print group bodies so we cut off after the first line.
59 string def = field->DebugString();
60 printer->Print("// $def$\n",
61 "def", def.substr(0, def.find_first_of('\n')));
62 }
63
64 struct FieldOrderingByNumber {
operator ()google::protobuf::compiler::javamicro::__anonb8518ae30111::FieldOrderingByNumber65 inline bool operator()(const FieldDescriptor* a,
66 const FieldDescriptor* b) const {
67 return a->number() < b->number();
68 }
69 };
70
71 // Sort the fields of the given Descriptor by number into a new[]'d array
72 // and return it.
SortFieldsByNumber(const Descriptor * descriptor)73 const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
74 const FieldDescriptor** fields =
75 new const FieldDescriptor*[descriptor->field_count()];
76 for (int i = 0; i < descriptor->field_count(); i++) {
77 fields[i] = descriptor->field(i);
78 }
79 sort(fields, fields + descriptor->field_count(),
80 FieldOrderingByNumber());
81 return fields;
82 }
83
84 // Get an identifier that uniquely identifies this type within the file.
85 // This is used to declare static variables related to this type at the
86 // outermost file scope.
UniqueFileScopeIdentifier(const Descriptor * descriptor)87 string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
88 return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
89 }
90
91 // Returns true if the message type has any required fields. If it doesn't,
92 // we can optimize out calls to its isInitialized() method.
93 //
94 // already_seen is used to avoid checking the same type multiple times
95 // (and also to protect against recursion).
HasRequiredFields(const Descriptor * type,hash_set<const Descriptor * > * already_seen)96 static bool HasRequiredFields(
97 const Descriptor* type,
98 hash_set<const Descriptor*>* already_seen) {
99 if (already_seen->count(type) > 0) {
100 // The type is already in cache. This means that either:
101 // a. The type has no required fields.
102 // b. We are in the midst of checking if the type has required fields,
103 // somewhere up the stack. In this case, we know that if the type
104 // has any required fields, they'll be found when we return to it,
105 // and the whole call to HasRequiredFields() will return true.
106 // Therefore, we don't have to check if this type has required fields
107 // here.
108 return false;
109 }
110 already_seen->insert(type);
111
112 // If the type has extensions, an extension with message type could contain
113 // required fields, so we have to be conservative and assume such an
114 // extension exists.
115 if (type->extension_range_count() > 0) return true;
116
117 for (int i = 0; i < type->field_count(); i++) {
118 const FieldDescriptor* field = type->field(i);
119 if (field->is_required()) {
120 return true;
121 }
122 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
123 if (HasRequiredFields(field->message_type(), already_seen)) {
124 return true;
125 }
126 }
127 }
128
129 return false;
130 }
131
HasRequiredFields(const Descriptor * type)132 static bool HasRequiredFields(const Descriptor* type) {
133 hash_set<const Descriptor*> already_seen;
134 return HasRequiredFields(type, &already_seen);
135 }
136
137 } // namespace
138
139 // ===================================================================
140
MessageGenerator(const Descriptor * descriptor,const Params & params)141 MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
142 : params_(params),
143 descriptor_(descriptor),
144 field_generators_(descriptor, params) {
145 }
146
~MessageGenerator()147 MessageGenerator::~MessageGenerator() {}
148
GenerateStaticVariables(io::Printer * printer)149 void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
150 // Generate static members for all nested types.
151 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
152 // TODO(kenton): Reuse MessageGenerator objects?
153 MessageGenerator(descriptor_->nested_type(i), params_)
154 .GenerateStaticVariables(printer);
155 }
156 }
157
GenerateStaticVariableInitializers(io::Printer * printer)158 void MessageGenerator::GenerateStaticVariableInitializers(
159 io::Printer* printer) {
160 // Generate static member initializers for all nested types.
161 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
162 // TODO(kenton): Reuse MessageGenerator objects?
163 MessageGenerator(descriptor_->nested_type(i), params_)
164 .GenerateStaticVariableInitializers(printer);
165 }
166
167 if (descriptor_->extension_count() != 0) {
168 GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
169 }
170 }
171
Generate(io::Printer * printer)172 void MessageGenerator::Generate(io::Printer* printer) {
173 bool is_own_file =
174 params_.java_multiple_files() || ((descriptor_->containing_type() == NULL)
175 && !params_.has_java_outer_classname(descriptor_->file()->name()));
176
177 #if 0
178 GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file;
179 GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null");
180 GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files();
181 GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name());
182 #endif
183
184 if ((descriptor_->extension_count() != 0)
185 || (descriptor_->extension_range_count() != 0)) {
186 GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
187 }
188
189 // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in
190 // the inner or outer class. This causes Java warnings, but is not fatal, so we suppress those
191 // warnings here in the class declaration.
192 printer->Print(
193 "@SuppressWarnings(\"hiding\")\n"
194 "public $modifiers$ final class $classname$ extends\n"
195 " com.google.protobuf.micro.MessageMicro {\n",
196 "modifiers", is_own_file ? "" : "static",
197 "classname", descriptor_->name());
198 printer->Indent();
199 printer->Print(
200 "public $classname$() {}\n"
201 "\n",
202 "classname", descriptor_->name());
203
204 // Nested types and extensions
205 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
206 EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
207 }
208
209 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
210 MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
211 }
212
213 // Fields
214 for (int i = 0; i < descriptor_->field_count(); i++) {
215 PrintFieldComment(printer, descriptor_->field(i));
216 printer->Print("public static final int $constant_name$ = $number$;\n",
217 "constant_name", FieldConstantName(descriptor_->field(i)),
218 "number", SimpleItoa(descriptor_->field(i)->number()));
219 field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
220 printer->Print("\n");
221 }
222
223 GenerateClear(printer);
224 GenerateIsInitialized(printer);
225 GenerateMessageSerializationMethods(printer);
226 GenerateMergeFromMethods(printer);
227 GenerateParseFromMethods(printer);
228
229 printer->Outdent();
230 printer->Print("}\n\n");
231 }
232
233 // ===================================================================
234
235 void MessageGenerator::
GenerateMessageSerializationMethods(io::Printer * printer)236 GenerateMessageSerializationMethods(io::Printer* printer) {
237 scoped_array<const FieldDescriptor*> sorted_fields(
238 SortFieldsByNumber(descriptor_));
239
240 if (descriptor_->extension_range_count() != 0) {
241 GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
242 }
243
244 // writeTo only throws an exception if it contains one or more fields to write
245 if (descriptor_->field_count() > 0) {
246 printer->Print(
247 "@Override\n"
248 "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n"
249 " throws java.io.IOException {\n");
250 } else {
251 printer->Print(
252 "@Override\n"
253 "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output) {\n");
254 }
255 printer->Indent();
256
257 // Output the fields in sorted order
258 for (int i = 0; i < descriptor_->field_count(); i++) {
259 GenerateSerializeOneField(printer, sorted_fields[i]);
260 }
261
262 printer->Outdent();
263 printer->Print(
264 "}\n"
265 "\n"
266 "private int cachedSize = -1;\n"
267 "@Override\n"
268 "public int getCachedSize() {\n"
269 " if (cachedSize < 0) {\n"
270 " // getSerializedSize sets cachedSize\n"
271 " getSerializedSize();\n"
272 " }\n"
273 " return cachedSize;\n"
274 "}\n"
275 "\n"
276 "@Override\n"
277 "public int getSerializedSize() {\n"
278 " int size = 0;\n");
279 printer->Indent();
280
281 for (int i = 0; i < descriptor_->field_count(); i++) {
282 field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
283 }
284
285 printer->Outdent();
286 printer->Print(
287 " cachedSize = size;\n"
288 " return size;\n"
289 "}\n"
290 "\n");
291 }
292
GenerateMergeFromMethods(io::Printer * printer)293 void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
294 scoped_array<const FieldDescriptor*> sorted_fields(
295 SortFieldsByNumber(descriptor_));
296
297 if (params_.java_use_vector()) {
298 printer->Print(
299 "@Override\n"
300 "public com.google.protobuf.micro.MessageMicro mergeFrom(\n"
301 " com.google.protobuf.micro.CodedInputStreamMicro input)\n"
302 " throws java.io.IOException {\n",
303 "classname", descriptor_->name());
304 } else {
305 printer->Print(
306 "@Override\n"
307 "public $classname$ mergeFrom(\n"
308 " com.google.protobuf.micro.CodedInputStreamMicro input)\n"
309 " throws java.io.IOException {\n",
310 "classname", descriptor_->name());
311 }
312 printer->Indent();
313
314 printer->Print(
315 "while (true) {\n");
316 printer->Indent();
317
318 printer->Print(
319 "int tag = input.readTag();\n"
320 "switch (tag) {\n");
321 printer->Indent();
322
323 printer->Print(
324 "case 0:\n" // zero signals EOF / limit reached
325 " return this;\n"
326 "default: {\n"
327 " if (!parseUnknownField(input, tag)) {\n"
328 " return this;\n" // it's an endgroup tag
329 " }\n"
330 " break;\n"
331 "}\n");
332
333 for (int i = 0; i < descriptor_->field_count(); i++) {
334 const FieldDescriptor* field = sorted_fields[i];
335 uint32 tag = WireFormatLite::MakeTag(field->number(),
336 WireFormat::WireTypeForField(field));
337
338 printer->Print(
339 "case $tag$: {\n",
340 "tag", SimpleItoa(tag));
341 printer->Indent();
342
343 field_generators_.get(field).GenerateParsingCode(printer);
344
345 printer->Outdent();
346 printer->Print(
347 " break;\n"
348 "}\n");
349 }
350
351 printer->Outdent();
352 printer->Outdent();
353 printer->Outdent();
354 printer->Print(
355 " }\n" // switch (tag)
356 " }\n" // while (true)
357 "}\n"
358 "\n");
359 }
360
361 void MessageGenerator::
GenerateParseFromMethods(io::Printer * printer)362 GenerateParseFromMethods(io::Printer* printer) {
363 bool is_own_file =
364 descriptor_->containing_type() == NULL;
365
366 // Note: These are separate from GenerateMessageSerializationMethods()
367 // because they need to be generated even for messages that are optimized
368 // for code size.
369 printer->Print(
370 "public $static$ $classname$ parseFrom(byte[] data)\n"
371 " throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n"
372 " return ($classname$) (new $classname$().mergeFrom(data));\n"
373 "}\n"
374 "\n"
375 "public $static$ $classname$ parseFrom(\n"
376 " com.google.protobuf.micro.CodedInputStreamMicro input)\n"
377 " throws java.io.IOException {\n"
378 " return new $classname$().mergeFrom(input);\n"
379 "}\n"
380 "\n",
381 "static", (is_own_file ? "static" : ""),
382 "classname", descriptor_->name());
383 }
384
GenerateSerializeOneField(io::Printer * printer,const FieldDescriptor * field)385 void MessageGenerator::GenerateSerializeOneField(
386 io::Printer* printer, const FieldDescriptor* field) {
387 field_generators_.get(field).GenerateSerializationCode(printer);
388 }
389
GenerateClear(io::Printer * printer)390 void MessageGenerator::GenerateClear(io::Printer* printer) {
391 printer->Print(
392 "public final $classname$ clear() {\n",
393 "classname", descriptor_->name());
394 printer->Indent();
395
396 // Call clear for all of the fields.
397 for (int i = 0; i < descriptor_->field_count(); i++) {
398 const FieldDescriptor* field = descriptor_->field(i);
399
400 printer->Print(
401 "clear$name$();\n",
402 "name", UnderscoresToCapitalizedCamelCase(field));
403 }
404
405 printer->Outdent();
406 printer->Print(
407 " cachedSize = -1;\n"
408 " return this;\n"
409 "}\n"
410 "\n");
411 }
412
413
GenerateIsInitialized(io::Printer * printer)414 void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
415 printer->Print(
416 "public final boolean isInitialized() {\n");
417 printer->Indent();
418
419 // Check that all required fields in this message are set.
420 // TODO(kenton): We can optimize this when we switch to putting all the
421 // "has" fields into a single bitfield.
422 for (int i = 0; i < descriptor_->field_count(); i++) {
423 const FieldDescriptor* field = descriptor_->field(i);
424
425 if (field->is_required()) {
426 printer->Print(
427 "if (!has$name$) return false;\n",
428 "name", UnderscoresToCapitalizedCamelCase(field));
429 }
430 }
431
432 // Now check that all embedded messages are initialized.
433 for (int i = 0; i < descriptor_->field_count(); i++) {
434 const FieldDescriptor* field = descriptor_->field(i);
435 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
436 HasRequiredFields(field->message_type())) {
437 switch (field->label()) {
438 case FieldDescriptor::LABEL_REQUIRED:
439 printer->Print(
440 "if (!get$name$().isInitialized()) return false;\n",
441 "type", ClassName(params_, field->message_type()),
442 "name", UnderscoresToCapitalizedCamelCase(field));
443 break;
444 case FieldDescriptor::LABEL_OPTIONAL:
445 printer->Print(
446 "if (has$name$()) {\n"
447 " if (!get$name$().isInitialized()) return false;\n"
448 "}\n",
449 "type", ClassName(params_, field->message_type()),
450 "name", UnderscoresToCapitalizedCamelCase(field));
451 break;
452 case FieldDescriptor::LABEL_REPEATED:
453 if (params_.java_use_vector()) {
454 printer->Print(
455 "for (int i = 0; i < get$name$List().size(); i++) {\n"
456 " if (get$name$(i).isInitialized()) return false;\n"
457 "}\n",
458 "type", ClassName(params_, field->message_type()),
459 "name", UnderscoresToCapitalizedCamelCase(field));
460 } else {
461 printer->Print(
462 "for ($type$ element : get$name$List()) {\n"
463 " if (!element.isInitialized()) return false;\n"
464 "}\n",
465 "type", ClassName(params_, field->message_type()),
466 "name", UnderscoresToCapitalizedCamelCase(field));
467 }
468 break;
469 }
470 }
471 }
472
473 if (descriptor_->extension_range_count() > 0) {
474 printer->Print(
475 "if (!extensionsAreInitialized()) return false;\n");
476 }
477
478 printer->Outdent();
479 printer->Print(
480 " return true;\n"
481 "}\n"
482 "\n");
483 }
484
485 // ===================================================================
486
487 } // namespace javamicro
488 } // namespace compiler
489 } // namespace protobuf
490 } // namespace google
491