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 <google/protobuf/compiler/javanano/javanano_field.h>
36#include <google/protobuf/compiler/javanano/javanano_helpers.h>
37#include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
38#include <google/protobuf/compiler/javanano/javanano_enum_field.h>
39#include <google/protobuf/compiler/javanano/javanano_map_field.h>
40#include <google/protobuf/compiler/javanano/javanano_message_field.h>
41#include <google/protobuf/stubs/common.h>
42
43namespace google {
44namespace protobuf {
45namespace compiler {
46namespace javanano {
47
48FieldGenerator::~FieldGenerator() {}
49
50bool FieldGenerator::SavedDefaultNeeded() const {
51  // No saved default for this field by default.
52  // Subclasses whose instances may need saved defaults will override this
53  // and return the appropriate value.
54  return false;
55}
56
57void FieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const {
58  // No saved default for this field by default.
59  // Subclasses whose instances may need saved defaults will override this
60  // and generate the appropriate init code to the printer.
61}
62
63void FieldGenerator::GenerateMergingCodeFromPacked(io::Printer* printer) const {
64  // Reaching here indicates a bug. Cases are:
65  //   - This FieldGenerator should support packing, but this method should be
66  //     overridden.
67  //   - This FieldGenerator doesn't support packing, and this method should
68  //     never have been called.
69  GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() "
70             << "called on field generator that does not support packing.";
71}
72
73// =============================================
74
75FieldGeneratorMap::FieldGeneratorMap(
76    const Descriptor* descriptor, const Params &params)
77  : descriptor_(descriptor),
78    field_generators_(
79      new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
80
81  int next_has_bit_index = 0;
82  bool saved_defaults_needed = false;
83  // Construct all the FieldGenerators.
84  for (int i = 0; i < descriptor->field_count(); i++) {
85    FieldGenerator* field_generator = MakeGenerator(
86        descriptor->field(i), params, &next_has_bit_index);
87    saved_defaults_needed = saved_defaults_needed
88        || field_generator->SavedDefaultNeeded();
89    field_generators_[i].reset(field_generator);
90  }
91  total_bits_ = next_has_bit_index;
92  saved_defaults_needed_ = saved_defaults_needed;
93}
94
95FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
96    const Params &params, int* next_has_bit_index) {
97  JavaType java_type = GetJavaType(field);
98  if (field->is_repeated()) {
99    switch (java_type) {
100      case JAVATYPE_MESSAGE:
101        if (IsMapEntry(field->message_type())) {
102          return new MapFieldGenerator(field, params);
103        } else {
104          return new RepeatedMessageFieldGenerator(field, params);
105        }
106      case JAVATYPE_ENUM:
107        return new RepeatedEnumFieldGenerator(field, params);
108      default:
109        return new RepeatedPrimitiveFieldGenerator(field, params);
110    }
111  } else if (field->containing_oneof()) {
112    switch (java_type) {
113      case JAVATYPE_MESSAGE:
114        return new MessageOneofFieldGenerator(field, params);
115      case JAVATYPE_ENUM:
116      default:
117        return new PrimitiveOneofFieldGenerator(field, params);
118    }
119  } else if (params.optional_field_accessors() && field->is_optional()
120      && java_type != JAVATYPE_MESSAGE) {
121    // We need a has-bit for each primitive/enum field because their default
122    // values could be same as explicitly set values. But we don't need it
123    // for a message field because they have no defaults and Nano uses 'null'
124    // for unset messages, which cannot be set explicitly.
125    switch (java_type) {
126      case JAVATYPE_ENUM:
127        return new AccessorEnumFieldGenerator(
128            field, params, (*next_has_bit_index)++);
129      default:
130        return new AccessorPrimitiveFieldGenerator(
131            field, params, (*next_has_bit_index)++);
132    }
133  } else {
134    switch (java_type) {
135      case JAVATYPE_MESSAGE:
136        return new MessageFieldGenerator(field, params);
137      case JAVATYPE_ENUM:
138        return new EnumFieldGenerator(field, params);
139      default:
140        return new PrimitiveFieldGenerator(field, params);
141    }
142  }
143}
144
145FieldGeneratorMap::~FieldGeneratorMap() {}
146
147const FieldGenerator& FieldGeneratorMap::get(
148    const FieldDescriptor* field) const {
149  GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
150  return *field_generators_[field->index()];
151}
152
153void SetCommonOneofVariables(const FieldDescriptor* descriptor,
154                             map<string, string>* variables) {
155  (*variables)["oneof_name"] =
156      UnderscoresToCamelCase(descriptor->containing_oneof());
157  (*variables)["oneof_capitalized_name"] =
158      UnderscoresToCapitalizedCamelCase(descriptor->containing_oneof());
159  (*variables)["oneof_index"] =
160      SimpleItoa(descriptor->containing_oneof()->index());
161  (*variables)["set_oneof_case"] =
162      "this." + (*variables)["oneof_name"] +
163      "Case_ = " + SimpleItoa(descriptor->number());
164  (*variables)["clear_oneof_case"] =
165      "this." + (*variables)["oneof_name"] + "Case_ = 0";
166  (*variables)["has_oneof_case"] =
167      "this." + (*variables)["oneof_name"] + "Case_ == " +
168      SimpleItoa(descriptor->number());
169}
170
171void GenerateOneofFieldEquals(const FieldDescriptor* descriptor,
172                              const map<string, string>& variables,
173                              io::Printer* printer) {
174  if (GetJavaType(descriptor) == JAVATYPE_BYTES) {
175    printer->Print(variables,
176      "if (this.has$capitalized_name$()) {\n"
177      "  if (!java.util.Arrays.equals((byte[]) this.$oneof_name$_,\n"
178      "                               (byte[]) other.$oneof_name$_)) {\n"
179      "    return false;\n"
180      "  }\n"
181      "}\n");
182  } else {
183    printer->Print(variables,
184      "if (this.has$capitalized_name$()) {\n"
185      "  if (!this.$oneof_name$_.equals(other.$oneof_name$_)) {\n"
186      "    return false;\n"
187      "  }\n"
188      "}\n");
189  }
190}
191
192void GenerateOneofFieldHashCode(const FieldDescriptor* descriptor,
193                                const map<string, string>& variables,
194                                io::Printer* printer) {
195  if (GetJavaType(descriptor) == JAVATYPE_BYTES) {
196    printer->Print(variables,
197      "result = 31 * result + ($has_oneof_case$\n"
198      "   ? java.util.Arrays.hashCode((byte[]) this.$oneof_name$_) : 0);\n");
199  } else {
200    printer->Print(variables,
201      "result = 31 * result +\n"
202      "  ($has_oneof_case$ ? this.$oneof_name$_.hashCode() : 0);\n");
203  }
204}
205
206}  // namespace javanano
207}  // namespace compiler
208}  // namespace protobuf
209}  // namespace google
210