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/java/java_enum_field.h> 39#include <google/protobuf/stubs/common.h> 40#include <google/protobuf/compiler/java/java_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 java { 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 FieldDescriptor* descriptor, 55 map<string, string>* variables) { 56 (*variables)["name"] = 57 UnderscoresToCamelCase(descriptor); 58 (*variables)["capitalized_name"] = 59 UnderscoresToCapitalizedCamelCase(descriptor); 60 (*variables)["number"] = SimpleItoa(descriptor->number()); 61 (*variables)["type"] = ClassName(descriptor->enum_type()); 62 (*variables)["default"] = DefaultValue(descriptor); 63 (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); 64 (*variables)["tag_size"] = SimpleItoa( 65 internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); 66} 67 68} // namespace 69 70// =================================================================== 71 72EnumFieldGenerator:: 73EnumFieldGenerator(const FieldDescriptor* descriptor) 74 : descriptor_(descriptor) { 75 SetEnumVariables(descriptor, &variables_); 76} 77 78EnumFieldGenerator::~EnumFieldGenerator() {} 79 80void EnumFieldGenerator:: 81GenerateMembers(io::Printer* printer) const { 82 printer->Print(variables_, 83 "private boolean has$capitalized_name$;\n" 84 "private $type$ $name$_;\n" 85 "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" 86 "public $type$ get$capitalized_name$() { return $name$_; }\n"); 87} 88 89void EnumFieldGenerator:: 90GenerateBuilderMembers(io::Printer* printer) const { 91 printer->Print(variables_, 92 "public boolean has$capitalized_name$() {\n" 93 " return result.has$capitalized_name$();\n" 94 "}\n" 95 "public $type$ get$capitalized_name$() {\n" 96 " return result.get$capitalized_name$();\n" 97 "}\n" 98 "public Builder set$capitalized_name$($type$ value) {\n" 99 " if (value == null) {\n" 100 " throw new NullPointerException();\n" 101 " }\n" 102 " result.has$capitalized_name$ = true;\n" 103 " result.$name$_ = value;\n" 104 " return this;\n" 105 "}\n" 106 "public Builder clear$capitalized_name$() {\n" 107 " result.has$capitalized_name$ = false;\n" 108 " result.$name$_ = $default$;\n" 109 " return this;\n" 110 "}\n"); 111} 112 113void EnumFieldGenerator:: 114GenerateInitializationCode(io::Printer* printer) const { 115 printer->Print(variables_, "$name$_ = $default$;\n"); 116} 117 118void EnumFieldGenerator:: 119GenerateMergingCode(io::Printer* printer) const { 120 printer->Print(variables_, 121 "if (other.has$capitalized_name$()) {\n" 122 " set$capitalized_name$(other.get$capitalized_name$());\n" 123 "}\n"); 124} 125 126void EnumFieldGenerator:: 127GenerateBuildingCode(io::Printer* printer) const { 128 // Nothing to do here for enum types. 129} 130 131void EnumFieldGenerator:: 132GenerateParsingCode(io::Printer* printer) const { 133 printer->Print(variables_, 134 "int rawValue = input.readEnum();\n" 135 "$type$ value = $type$.valueOf(rawValue);\n"); 136 if (HasUnknownFields(descriptor_->containing_type())) { 137 printer->Print(variables_, 138 "if (value == null) {\n" 139 " unknownFields.mergeVarintField($number$, rawValue);\n" 140 "} else {\n"); 141 } else { 142 printer->Print(variables_, 143 "if (value != null) {\n"); 144 } 145 printer->Print(variables_, 146 " set$capitalized_name$(value);\n" 147 "}\n"); 148} 149 150void EnumFieldGenerator:: 151GenerateSerializationCode(io::Printer* printer) const { 152 printer->Print(variables_, 153 "if (has$capitalized_name$()) {\n" 154 " output.writeEnum($number$, get$capitalized_name$().getNumber());\n" 155 "}\n"); 156} 157 158void EnumFieldGenerator:: 159GenerateSerializedSizeCode(io::Printer* printer) const { 160 printer->Print(variables_, 161 "if (has$capitalized_name$()) {\n" 162 " size += com.google.protobuf.CodedOutputStream\n" 163 " .computeEnumSize($number$, get$capitalized_name$().getNumber());\n" 164 "}\n"); 165} 166 167string EnumFieldGenerator::GetBoxedType() const { 168 return ClassName(descriptor_->enum_type()); 169} 170 171// =================================================================== 172 173RepeatedEnumFieldGenerator:: 174RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor) 175 : descriptor_(descriptor) { 176 SetEnumVariables(descriptor, &variables_); 177} 178 179RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} 180 181void RepeatedEnumFieldGenerator:: 182GenerateMembers(io::Printer* printer) const { 183 printer->Print(variables_, 184 "private java.util.List<$type$> $name$_ =\n" 185 " java.util.Collections.emptyList();\n" 186 "public java.util.List<$type$> get$capitalized_name$List() {\n" 187 " return $name$_;\n" // note: unmodifiable list 188 "}\n" 189 "public int get$capitalized_name$Count() { return $name$_.size(); }\n" 190 "public $type$ get$capitalized_name$(int index) {\n" 191 " return $name$_.get(index);\n" 192 "}\n"); 193 194 if (descriptor_->options().packed() && 195 HasGeneratedMethods(descriptor_->containing_type())) { 196 printer->Print(variables_, 197 "private int $name$MemoizedSerializedSize;\n"); 198 } 199} 200 201void RepeatedEnumFieldGenerator:: 202GenerateBuilderMembers(io::Printer* printer) const { 203 printer->Print(variables_, 204 // Note: We return an unmodifiable list because otherwise the caller 205 // could hold on to the returned list and modify it after the message 206 // has been built, thus mutating the message which is supposed to be 207 // immutable. 208 "public java.util.List<$type$> get$capitalized_name$List() {\n" 209 " return java.util.Collections.unmodifiableList(result.$name$_);\n" 210 "}\n" 211 "public int get$capitalized_name$Count() {\n" 212 " return result.get$capitalized_name$Count();\n" 213 "}\n" 214 "public $type$ get$capitalized_name$(int index) {\n" 215 " return result.get$capitalized_name$(index);\n" 216 "}\n" 217 "public Builder set$capitalized_name$(int index, $type$ value) {\n" 218 " if (value == null) {\n" 219 " throw new NullPointerException();\n" 220 " }\n" 221 " result.$name$_.set(index, value);\n" 222 " return this;\n" 223 "}\n" 224 "public Builder add$capitalized_name$($type$ value) {\n" 225 " if (value == null) {\n" 226 " throw new NullPointerException();\n" 227 " }\n" 228 " if (result.$name$_.isEmpty()) {\n" 229 " result.$name$_ = new java.util.ArrayList<$type$>();\n" 230 " }\n" 231 " result.$name$_.add(value);\n" 232 " return this;\n" 233 "}\n" 234 "public Builder addAll$capitalized_name$(\n" 235 " java.lang.Iterable<? extends $type$> values) {\n" 236 " if (result.$name$_.isEmpty()) {\n" 237 " result.$name$_ = new java.util.ArrayList<$type$>();\n" 238 " }\n" 239 " super.addAll(values, result.$name$_);\n" 240 " return this;\n" 241 "}\n" 242 "public Builder clear$capitalized_name$() {\n" 243 " result.$name$_ = java.util.Collections.emptyList();\n" 244 " return this;\n" 245 "}\n"); 246} 247 248void RepeatedEnumFieldGenerator:: 249GenerateInitializationCode(io::Printer* printer) const { 250 // Initialized inline. 251} 252 253void RepeatedEnumFieldGenerator:: 254GenerateMergingCode(io::Printer* printer) const { 255 printer->Print(variables_, 256 "if (!other.$name$_.isEmpty()) {\n" 257 " if (result.$name$_.isEmpty()) {\n" 258 " result.$name$_ = new java.util.ArrayList<$type$>();\n" 259 " }\n" 260 " result.$name$_.addAll(other.$name$_);\n" 261 "}\n"); 262} 263 264void RepeatedEnumFieldGenerator:: 265GenerateBuildingCode(io::Printer* printer) const { 266 printer->Print(variables_, 267 "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n" 268 " result.$name$_ =\n" 269 " java.util.Collections.unmodifiableList(result.$name$_);\n" 270 "}\n"); 271} 272 273void RepeatedEnumFieldGenerator:: 274GenerateParsingCode(io::Printer* printer) const { 275 // Read and store the enum 276 printer->Print(variables_, 277 "int rawValue = input.readEnum();\n" 278 "$type$ value = $type$.valueOf(rawValue);\n"); 279 if (HasUnknownFields(descriptor_->containing_type())) { 280 printer->Print(variables_, 281 "if (value == null) {\n" 282 " unknownFields.mergeVarintField($number$, rawValue);\n" 283 "} else {\n"); 284 } else { 285 printer->Print(variables_, 286 "if (value != null) {\n"); 287 } 288 printer->Print(variables_, 289 " add$capitalized_name$(value);\n" 290 "}\n"); 291} 292 293void RepeatedEnumFieldGenerator:: 294GenerateParsingCodeFromPacked(io::Printer* printer) const { 295 // Wrap GenerateParsingCode's contents with a while loop. 296 297 printer->Print(variables_, 298 "int length = input.readRawVarint32();\n" 299 "int oldLimit = input.pushLimit(length);\n" 300 "while(input.getBytesUntilLimit() > 0) {\n"); 301 printer->Indent(); 302 303 GenerateParsingCode(printer); 304 305 printer->Outdent(); 306 printer->Print(variables_, 307 "}\n" 308 "input.popLimit(oldLimit);\n"); 309} 310 311void RepeatedEnumFieldGenerator:: 312GenerateSerializationCode(io::Printer* printer) const { 313 if (descriptor_->options().packed()) { 314 printer->Print(variables_, 315 "if (get$capitalized_name$List().size() > 0) {\n" 316 " output.writeRawVarint32($tag$);\n" 317 " output.writeRawVarint32($name$MemoizedSerializedSize);\n" 318 "}\n" 319 "for ($type$ element : get$capitalized_name$List()) {\n" 320 " output.writeEnumNoTag(element.getNumber());\n" 321 "}\n"); 322 } else { 323 printer->Print(variables_, 324 "for ($type$ element : get$capitalized_name$List()) {\n" 325 " output.writeEnum($number$, element.getNumber());\n" 326 "}\n"); 327 } 328} 329 330void RepeatedEnumFieldGenerator:: 331GenerateSerializedSizeCode(io::Printer* printer) const { 332 printer->Print(variables_, 333 "{\n" 334 " int dataSize = 0;\n"); 335 printer->Indent(); 336 337 printer->Print(variables_, 338 "for ($type$ element : get$capitalized_name$List()) {\n" 339 " dataSize += com.google.protobuf.CodedOutputStream\n" 340 " .computeEnumSizeNoTag(element.getNumber());\n" 341 "}\n"); 342 printer->Print( 343 "size += dataSize;\n"); 344 if (descriptor_->options().packed()) { 345 printer->Print(variables_, 346 "if (!get$capitalized_name$List().isEmpty()) {" 347 " size += $tag_size$;\n" 348 " size += com.google.protobuf.CodedOutputStream\n" 349 " .computeRawVarint32Size(dataSize);\n" 350 "}"); 351 } else { 352 printer->Print(variables_, 353 "size += $tag_size$ * get$capitalized_name$List().size();\n"); 354 } 355 356 // cache the data size for packed fields. 357 if (descriptor_->options().packed()) { 358 printer->Print(variables_, 359 "$name$MemoizedSerializedSize = dataSize;\n"); 360 } 361 362 printer->Outdent(); 363 printer->Print("}\n"); 364} 365 366string RepeatedEnumFieldGenerator::GetBoxedType() const { 367 return ClassName(descriptor_->enum_type()); 368} 369 370} // namespace java 371} // namespace compiler 372} // namespace protobuf 373} // namespace google 374