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_message_field.h>
39#include <google/protobuf/compiler/javanano/javanano_helpers.h>
40#include <google/protobuf/io/printer.h>
41#include <google/protobuf/wire_format.h>
42#include <google/protobuf/stubs/strutil.h>
43
44namespace google {
45namespace protobuf {
46namespace compiler {
47namespace javanano {
48
49using internal::WireFormat;
50using internal::WireFormatLite;
51
52namespace {
53
54// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
55//   repeat code between this and the other field types.
56void SetMessageVariables(const Params& params,
57    const FieldDescriptor* descriptor, map<string, string>* variables) {
58  (*variables)["name"] =
59    RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
60  (*variables)["capitalized_name"] =
61    RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor));
62  (*variables)["number"] = SimpleItoa(descriptor->number());
63  (*variables)["type"] = ClassName(params, descriptor->message_type());
64  (*variables)["group_or_message"] =
65    (descriptor->type() == FieldDescriptor::TYPE_GROUP) ?
66    "Group" : "Message";
67  (*variables)["message_name"] = descriptor->containing_type()->name();
68  //(*variables)["message_type"] = descriptor->message_type()->name();
69  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
70}
71
72}  // namespace
73
74// ===================================================================
75
76MessageFieldGenerator::
77MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
78  : FieldGenerator(params), descriptor_(descriptor) {
79  SetMessageVariables(params, descriptor, &variables_);
80}
81
82MessageFieldGenerator::~MessageFieldGenerator() {}
83
84void MessageFieldGenerator::
85GenerateMembers(io::Printer* printer) const {
86  printer->Print(variables_,
87    "public $type$ $name$ = null;\n");
88}
89
90void MessageFieldGenerator::
91GenerateParsingCode(io::Printer* printer) const {
92  printer->Print(variables_,
93    "this.$name$ = new $type$();\n");
94
95  if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
96    printer->Print(variables_,
97      "input.readGroup(this.$name$, $number$);\n");
98  } else {
99    printer->Print(variables_,
100      "input.readMessage(this.$name$);\n");
101  }
102}
103
104void MessageFieldGenerator::
105GenerateSerializationCode(io::Printer* printer) const {
106  printer->Print(variables_,
107    "if (this.$name$ != null) {\n"
108    "  output.write$group_or_message$($number$, this.$name$);\n"
109    "}\n");
110}
111
112void MessageFieldGenerator::
113GenerateSerializedSizeCode(io::Printer* printer) const {
114  printer->Print(variables_,
115    "if (this.$name$ != null) {\n"
116    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
117    "    .compute$group_or_message$Size($number$, this.$name$);\n"
118    "}\n");
119}
120
121string MessageFieldGenerator::GetBoxedType() const {
122  return ClassName(params_, descriptor_->message_type());
123}
124
125// ===================================================================
126
127RepeatedMessageFieldGenerator::
128RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
129  : FieldGenerator(params), descriptor_(descriptor) {
130  SetMessageVariables(params, descriptor, &variables_);
131}
132
133RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
134
135void RepeatedMessageFieldGenerator::
136GenerateMembers(io::Printer* printer) const {
137  printer->Print(variables_,
138    "public $type$[] $name$ = $type$.EMPTY_ARRAY;\n");
139}
140
141void RepeatedMessageFieldGenerator::
142GenerateParsingCode(io::Printer* printer) const {
143  // First, figure out the length of the array, then parse.
144  printer->Print(variables_,
145    "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n"
146    "int i = this.$name$.length;\n"
147    "$type$[] newArray = new $type$[i + arrayLength];\n"
148    "System.arraycopy(this.$name$, 0, newArray, 0, i);\n"
149    "this.$name$ = newArray;\n"
150    "for (; i < this.$name$.length - 1; i++) {\n"
151    "  this.$name$[i] = new $type$();\n");
152
153  if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
154    printer->Print(variables_,
155      "  input.readGroup(this.$name$[i], $number$);\n");
156  } else {
157    printer->Print(variables_,
158      "  input.readMessage(this.$name$[i]);\n");
159  }
160
161  printer->Print(variables_,
162    "  input.readTag();\n"
163    "}\n"
164    "// Last one without readTag.\n"
165    "this.$name$[i] = new $type$();\n");
166
167  if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
168    printer->Print(variables_,
169      "input.readGroup(this.$name$[i], $number$);\n");
170  } else {
171    printer->Print(variables_,
172      "input.readMessage(this.$name$[i]);\n");
173  }
174}
175
176void RepeatedMessageFieldGenerator::
177GenerateSerializationCode(io::Printer* printer) const {
178  printer->Print(variables_,
179    "for ($type$ element : this.$name$) {\n"
180    "  output.write$group_or_message$($number$, element);\n"
181    "}\n");
182}
183
184void RepeatedMessageFieldGenerator::
185GenerateSerializedSizeCode(io::Printer* printer) const {
186  printer->Print(variables_,
187    "for ($type$ element : this.$name$) {\n"
188    "  size += com.google.protobuf.nano.CodedOutputByteBufferNano\n"
189    "    .compute$group_or_message$Size($number$, element);\n"
190    "}\n");
191}
192
193string RepeatedMessageFieldGenerator::GetBoxedType() const {
194  return ClassName(params_, descriptor_->message_type());
195}
196
197}  // namespace javanano
198}  // namespace compiler
199}  // namespace protobuf
200}  // namespace google
201