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