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 <map>
36#include <string>
37
38#include <google/protobuf/compiler/javanano/javanano_enum_field.h>
39#include <google/protobuf/stubs/common.h>
40#include <google/protobuf/compiler/javanano/javanano_helpers.h>
41#include <google/protobuf/io/printer.h>
42#include <google/protobuf/wire_format.h>
43#include <google/protobuf/stubs/strutil.h>
44
45namespace google {
46namespace protobuf {
47namespace compiler {
48namespace javanano {
49
50namespace {
51
52// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
53//   repeat code between this and the other field types.
54void SetEnumVariables(const Params& params,
55    const FieldDescriptor* descriptor, map<string, string>* variables) {
56  (*variables)["name"] =
57    RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
58  (*variables)["capitalized_name"] =
59    RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
60  (*variables)["number"] = SimpleItoa(descriptor->number());
61  if (params.use_reference_types_for_primitives()
62      && !params.reftypes_primitive_enums()
63      && !descriptor->is_repeated()) {
64    (*variables)["type"] = "java.lang.Integer";
65    (*variables)["default"] = "null";
66  } else {
67    (*variables)["type"] = "int";
68    (*variables)["default"] = DefaultValue(params, descriptor);
69  }
70  (*variables)["repeated_default"] =
71      "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY";
72  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
73  (*variables)["tag_size"] = SimpleItoa(
74      internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
75  (*variables)["non_packed_tag"] = SimpleItoa(
76      internal::WireFormatLite::MakeTag(descriptor->number(),
77          internal::WireFormat::WireTypeForFieldType(descriptor->type())));
78  (*variables)["message_name"] = descriptor->containing_type()->name();
79  const EnumDescriptor* enum_type = descriptor->enum_type();
80  (*variables)["message_type_intdef"] = "@"
81      + ToJavaName(params, enum_type->name(), true,
82          enum_type->containing_type(), enum_type->file());
83}
84
85void LoadEnumValues(const Params& params,
86    const EnumDescriptor* enum_descriptor, vector<string>* canonical_values) {
87  string enum_class_name = ClassName(params, enum_descriptor);
88  for (int i = 0; i < enum_descriptor->value_count(); i++) {
89    const EnumValueDescriptor* value = enum_descriptor->value(i);
90    const EnumValueDescriptor* canonical_value =
91        enum_descriptor->FindValueByNumber(value->number());
92    if (value == canonical_value) {
93      canonical_values->push_back(
94          enum_class_name + "." + RenameJavaKeywords(value->name()));
95    }
96  }
97}
98
99void PrintCaseLabels(
100    io::Printer* printer, const vector<string>& canonical_values) {
101  for (int i = 0; i < canonical_values.size(); i++) {
102    printer->Print(
103      "  case $value$:\n",
104      "value", canonical_values[i]);
105  }
106}
107
108}  // namespace
109
110// ===================================================================
111
112EnumFieldGenerator::
113EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
114  : FieldGenerator(params), descriptor_(descriptor) {
115  SetEnumVariables(params, descriptor, &variables_);
116  LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
117}
118
119EnumFieldGenerator::~EnumFieldGenerator() {}
120
121void EnumFieldGenerator::
122GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
123  if (params_.generate_intdefs()) {
124    printer->Print(variables_, "$message_type_intdef$\n");
125  }
126  printer->Print(variables_, "public $type$ $name$;\n");
127
128  if (params_.generate_has()) {
129    printer->Print(variables_,
130      "public boolean has$capitalized_name$;\n");
131  }
132}
133
134void EnumFieldGenerator::
135GenerateClearCode(io::Printer* printer) const {
136  printer->Print(variables_,
137    "$name$ = $default$;\n");
138
139  if (params_.generate_has()) {
140    printer->Print(variables_,
141      "has$capitalized_name$ = false;\n");
142  }
143}
144
145void EnumFieldGenerator::
146GenerateMergingCode(io::Printer* printer) const {
147  if (params_.store_unknown_fields()) {
148    printer->Print("int initialPos = input.getPosition();\n");
149  }
150  printer->Print(variables_,
151    "int value = input.readInt32();\n"
152    "switch (value) {\n");
153  PrintCaseLabels(printer, canonical_values_);
154  printer->Print(variables_,
155    "    this.$name$ = value;\n");
156  if (params_.generate_has()) {
157    printer->Print(variables_,
158      "    has$capitalized_name$ = true;\n");
159  }
160  printer->Print(
161    "    break;\n");
162  if (params_.store_unknown_fields()) {
163    // If storing unknown fields, store invalid values there.
164    // This is consistent with full protobuf, but note that if a client writes
165    // a new value to this field, both will be serialized on the wire, and
166    // other clients which are aware of unknown fields will see the previous
167    // value, not the new one.
168    printer->Print(
169      "  default:\n"
170      "    input.rewindToPosition(initialPos);\n"
171      "    storeUnknownField(input, tag);\n"
172      "    break;\n");
173  }
174  printer->Print("}\n");
175}
176
177void EnumFieldGenerator::
178GenerateSerializationCode(io::Printer* printer) const {
179  if (descriptor_->is_required() && !params_.generate_has()) {
180    // Always serialize a required field if we don't have the 'has' signal.
181    printer->Print(variables_,
182      "output.writeInt32($number$, this.$name$);\n");
183  } else {
184    if (params_.generate_has()) {
185      printer->Print(variables_,
186        "if (this.$name$ != $default$ || has$capitalized_name$) {\n");
187    } else {
188      printer->Print(variables_,
189        "if (this.$name$ != $default$) {\n");
190    }
191    printer->Print(variables_,
192      "  output.writeInt32($number$, this.$name$);\n"
193      "}\n");
194  }
195}
196
197void EnumFieldGenerator::
198GenerateSerializedSizeCode(io::Printer* printer) const {
199  if (descriptor_->is_required() && !params_.generate_has()) {
200    printer->Print(variables_,
201      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
202      "  .computeInt32Size($number$, this.$name$);\n");
203  } else {
204    if (params_.generate_has()) {
205      printer->Print(variables_,
206        "if (this.$name$ != $default$ || has$capitalized_name$) {\n");
207    } else {
208      printer->Print(variables_,
209        "if (this.$name$ != $default$) {\n");
210    }
211    printer->Print(variables_,
212      "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
213      "    .computeInt32Size($number$, this.$name$);\n"
214      "}\n");
215  }
216}
217
218void EnumFieldGenerator::GenerateEqualsCode(io::Printer* printer) const {
219  if (params_.use_reference_types_for_primitives()
220        && !params_.reftypes_primitive_enums()) {
221    printer->Print(variables_,
222      "if (this.$name$ == null) {\n"
223      "  if (other.$name$ != null) {\n"
224      "    return false;\n"
225      "  }\n"
226      "} else if (!this.$name$.equals(other.$name$)) {\n"
227      "  return false;"
228      "}\n");
229  } else {
230    // We define equality as serialized form equality. If generate_has(),
231    // then if the field value equals the default value in both messages,
232    // but one's 'has' field is set and the other's is not, the serialized
233    // forms are different and we should return false.
234    printer->Print(variables_,
235      "if (this.$name$ != other.$name$");
236    if (params_.generate_has()) {
237      printer->Print(variables_,
238        "\n"
239        "    || (this.$name$ == $default$\n"
240        "        && this.has$capitalized_name$ != other.has$capitalized_name$)");
241    }
242    printer->Print(") {\n"
243      "  return false;\n"
244      "}\n");
245  }
246}
247
248void EnumFieldGenerator::GenerateHashCodeCode(io::Printer* printer) const {
249  printer->Print(
250    "result = 31 * result + ");
251  if (params_.use_reference_types_for_primitives()
252        && !params_.reftypes_primitive_enums()) {
253    printer->Print(variables_,
254      "(this.$name$ == null ? 0 : this.$name$)");
255  } else {
256    printer->Print(variables_,
257      "this.$name$");
258  }
259  printer->Print(";\n");
260}
261
262// ===================================================================
263
264AccessorEnumFieldGenerator::
265AccessorEnumFieldGenerator(const FieldDescriptor* descriptor,
266    const Params& params, int has_bit_index)
267  : FieldGenerator(params), descriptor_(descriptor) {
268  SetEnumVariables(params, descriptor, &variables_);
269  LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
270  SetBitOperationVariables("has", has_bit_index, &variables_);
271}
272
273AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {}
274
275void AccessorEnumFieldGenerator::
276GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
277  printer->Print(variables_, "private int $name$_;\n");
278  if (params_.generate_intdefs()) {
279    printer->Print(variables_, "$message_type_intdef$\n");
280  }
281  printer->Print(variables_,
282    "public int get$capitalized_name$() {\n"
283    "  return $name$_;\n"
284    "}\n"
285    "public $message_name$ set$capitalized_name$(");
286  if (params_.generate_intdefs()) {
287    printer->Print(variables_,
288      "\n"
289      "    $message_type_intdef$ ");
290  }
291  printer->Print(variables_,
292    "int value) {\n"
293    "  $name$_ = value;\n"
294    "  $set_has$;\n"
295    "  return this;\n"
296    "}\n"
297    "public boolean has$capitalized_name$() {\n"
298    "  return $get_has$;\n"
299    "}\n"
300    "public $message_name$ clear$capitalized_name$() {\n"
301    "  $name$_ = $default$;\n"
302    "  $clear_has$;\n"
303    "  return this;\n"
304    "}\n");
305}
306
307void AccessorEnumFieldGenerator::
308GenerateClearCode(io::Printer* printer) const {
309  printer->Print(variables_,
310    "$name$_ = $default$;\n");
311}
312
313void AccessorEnumFieldGenerator::
314GenerateMergingCode(io::Printer* printer) const {
315  if (params_.store_unknown_fields()) {
316    printer->Print("int initialPos = input.getPosition();\n");
317  }
318  printer->Print(variables_,
319    "int value = input.readInt32();\n"
320    "switch (value) {\n");
321  PrintCaseLabels(printer, canonical_values_);
322  printer->Print(variables_,
323    "    $name$_ = value;\n"
324    "    $set_has$;\n"
325    "    break;\n");
326  if (params_.store_unknown_fields()) {
327    // If storing unknown fields, store invalid values there.
328    // This is consistent with full protobuf, but note that if a client writes
329    // a new value to this field, both will be serialized on the wire, and
330    // other clients which are aware of unknown fields will see the previous
331    // value, not the new one.
332    printer->Print(
333      "  default:\n"
334      "    input.rewindToPosition(initialPos);\n"
335      "    storeUnknownField(input, tag);\n"
336      "    break;\n");
337  }
338  printer->Print("}\n");
339}
340
341void AccessorEnumFieldGenerator::
342GenerateSerializationCode(io::Printer* printer) const {
343  printer->Print(variables_,
344    "if ($get_has$) {\n"
345    "  output.writeInt32($number$, $name$_);\n"
346    "}\n");
347}
348
349void AccessorEnumFieldGenerator::
350GenerateSerializedSizeCode(io::Printer* printer) const {
351  printer->Print(variables_,
352    "if ($get_has$) {\n"
353    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
354    "    .computeInt32Size($number$, $name$_);\n"
355    "}\n");
356}
357
358void AccessorEnumFieldGenerator::
359GenerateEqualsCode(io::Printer* printer) const {
360  printer->Print(variables_,
361    "if ($different_has$\n"
362    "    || $name$_ != other.$name$_) {\n"
363    "  return false;\n"
364    "}\n");
365}
366
367void AccessorEnumFieldGenerator::
368GenerateHashCodeCode(io::Printer* printer) const {
369  printer->Print(variables_,
370    "result = 31 * result + $name$_;\n");
371}
372
373// ===================================================================
374
375RepeatedEnumFieldGenerator::
376RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
377  : FieldGenerator(params), descriptor_(descriptor) {
378  SetEnumVariables(params, descriptor, &variables_);
379  LoadEnumValues(params, descriptor->enum_type(), &canonical_values_);
380}
381
382RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
383
384void RepeatedEnumFieldGenerator::
385GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const {
386  printer->Print(variables_,
387    "public $type$[] $name$;\n");
388}
389
390void RepeatedEnumFieldGenerator::
391GenerateClearCode(io::Printer* printer) const {
392  printer->Print(variables_,
393    "$name$ = $repeated_default$;\n");
394}
395
396void RepeatedEnumFieldGenerator::
397GenerateMergingCode(io::Printer* printer) const {
398  // First, figure out the maximum length of the array, then parse,
399  // and finally copy the valid values to the field.
400  printer->Print(variables_,
401    "int length = com.google.protobuf.nano.WireFormatNano\n"
402    "    .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n"
403    "int[] validValues = new int[length];\n"
404    "int validCount = 0;\n"
405    "for (int i = 0; i < length; i++) {\n"
406    "  if (i != 0) { // tag for first value already consumed.\n"
407    "    input.readTag();\n"
408    "  }\n");
409  if (params_.store_unknown_fields()) {
410    printer->Print("  int initialPos = input.getPosition();\n");
411  }
412  printer->Print(
413    "  int value = input.readInt32();\n"
414    "  switch (value) {\n");
415  printer->Indent();
416  PrintCaseLabels(printer, canonical_values_);
417  printer->Outdent();
418  printer->Print(variables_,
419    "      validValues[validCount++] = value;\n"
420    "      break;\n");
421  if (params_.store_unknown_fields()) {
422    // If storing unknown fields, store invalid values there.
423    // This is consistent with full protobuf. Note that this can lead to very
424    // strange behaviors if a value is serialized and reread, e.g. changes in
425    // value ordering.
426    printer->Print(
427      "    default:\n"
428      "      input.rewindToPosition(initialPos);\n"
429      "      storeUnknownField(input, tag);\n"
430      "      break;\n");
431  }
432  printer->Print(variables_,
433    "  }\n"
434    "}\n"
435    "if (validCount != 0) {\n"
436    "  int i = this.$name$ == null ? 0 : this.$name$.length;\n"
437    "  if (i == 0 && validCount == validValues.length) {\n"
438    "    this.$name$ = validValues;\n"
439    "  } else {\n"
440    "    int[] newArray = new int[i + validCount];\n"
441    "    if (i != 0) {\n"
442    "      java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
443    "    }\n"
444    "    java.lang.System.arraycopy(validValues, 0, newArray, i, validCount);\n"
445    "    this.$name$ = newArray;\n"
446    "  }\n"
447    "}\n");
448}
449
450void RepeatedEnumFieldGenerator::
451GenerateMergingCodeFromPacked(io::Printer* printer) const {
452  printer->Print(variables_,
453    "int bytes = input.readRawVarint32();\n"
454    "int limit = input.pushLimit(bytes);\n"
455    "// First pass to compute array length.\n"
456    "int arrayLength = 0;\n"
457    "int startPos = input.getPosition();\n"
458    "while (input.getBytesUntilLimit() > 0) {\n"
459    "  switch (input.readInt32()) {\n");
460  printer->Indent();
461  PrintCaseLabels(printer, canonical_values_);
462  printer->Outdent();
463  printer->Print(variables_,
464    "      arrayLength++;\n"
465    "      break;\n"
466    "  }\n"
467    "}\n"
468    "if (arrayLength != 0) {\n"
469    "  input.rewindToPosition(startPos);\n"
470    "  int i = this.$name$ == null ? 0 : this.$name$.length;\n"
471    "  int[] newArray = new int[i + arrayLength];\n"
472    "  if (i != 0) {\n"
473    "    java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
474    "  }\n"
475    "  while (input.getBytesUntilLimit() > 0) {\n");
476  if (params_.store_unknown_fields()) {
477    printer->Print("    int initialPos = input.getPosition();\n");
478  }
479  printer->Print(variables_,
480    "    int value = input.readInt32();\n"
481    "    switch (value) {\n");
482  printer->Indent();
483  printer->Indent();
484  PrintCaseLabels(printer, canonical_values_);
485  printer->Outdent();
486  printer->Outdent();
487  printer->Print(variables_,
488    "        newArray[i++] = value;\n"
489    "        break;\n");
490  if (params_.store_unknown_fields()) {
491    // If storing unknown fields, store invalid values there.
492    // This is consistent with full protobuf. Note that this can lead to very
493    // strange behaviors if a value is serialized and reread, e.g. changes in
494    // value ordering.
495    printer->Print(variables_,
496      "      default:\n"
497      "        input.rewindToPosition(initialPos);\n"
498      "        storeUnknownField(input, $non_packed_tag$);\n"
499      "        break;\n");
500  }
501  printer->Print(variables_,
502    "    }\n"
503    "  }\n"
504    "  this.$name$ = newArray;\n"
505    "}\n"
506    "input.popLimit(limit);\n");
507}
508
509void RepeatedEnumFieldGenerator::
510GenerateRepeatedDataSizeCode(io::Printer* printer) const {
511  // Creates a variable dataSize and puts the serialized size in there.
512  printer->Print(variables_,
513    "int dataSize = 0;\n"
514    "for (int i = 0; i < this.$name$.length; i++) {\n"
515    "  int element = this.$name$[i];\n"
516    "  dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
517    "      .computeInt32SizeNoTag(element);\n"
518    "}\n");
519}
520
521void RepeatedEnumFieldGenerator::
522GenerateSerializationCode(io::Printer* printer) const {
523  printer->Print(variables_,
524    "if (this.$name$ != null && this.$name$.length > 0) {\n");
525  printer->Indent();
526
527  if (descriptor_->options().packed()) {
528    GenerateRepeatedDataSizeCode(printer);
529    printer->Print(variables_,
530      "output.writeRawVarint32($tag$);\n"
531      "output.writeRawVarint32(dataSize);\n"
532      "for (int i = 0; i < this.$name$.length; i++) {\n"
533      "  output.writeRawVarint32(this.$name$[i]);\n"
534      "}\n");
535  } else {
536    printer->Print(variables_,
537      "for (int i = 0; i < this.$name$.length; i++) {\n"
538      "  output.writeInt32($number$, this.$name$[i]);\n"
539      "}\n");
540  }
541
542  printer->Outdent();
543  printer->Print(variables_,
544    "}\n");
545}
546
547void RepeatedEnumFieldGenerator::
548GenerateSerializedSizeCode(io::Printer* printer) const {
549  printer->Print(variables_,
550    "if (this.$name$ != null && this.$name$.length > 0) {\n");
551  printer->Indent();
552
553  GenerateRepeatedDataSizeCode(printer);
554
555  printer->Print(
556    "size += dataSize;\n");
557  if (descriptor_->options().packed()) {
558    printer->Print(variables_,
559      "size += $tag_size$;\n"
560      "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
561      "    .computeRawVarint32Size(dataSize);\n");
562  } else {
563    printer->Print(variables_,
564      "size += $tag_size$ * this.$name$.length;\n");
565  }
566
567  printer->Outdent();
568
569  printer->Print(
570    "}\n");
571}
572
573void RepeatedEnumFieldGenerator::
574GenerateFixClonedCode(io::Printer* printer) const {
575  printer->Print(variables_,
576    "if (this.$name$ != null && this.$name$.length > 0) {\n"
577    "  cloned.$name$ = this.$name$.clone();\n"
578    "}\n");
579}
580
581void RepeatedEnumFieldGenerator::
582GenerateEqualsCode(io::Printer* printer) const {
583  printer->Print(variables_,
584    "if (!com.google.protobuf.nano.InternalNano.equals(\n"
585    "    this.$name$, other.$name$)) {\n"
586    "  return false;\n"
587    "}\n");
588}
589
590void RepeatedEnumFieldGenerator::
591GenerateHashCodeCode(io::Printer* printer) const {
592  printer->Print(variables_,
593    "result = 31 * result\n"
594    "    + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n");
595}
596
597}  // namespace javanano
598}  // namespace compiler
599}  // namespace protobuf
600}  // namespace google
601