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 <math.h> 37#include <string> 38 39#include <google/protobuf/compiler/javanano/javanano_primitive_field.h> 40#include <google/protobuf/stubs/common.h> 41#include <google/protobuf/compiler/javanano/javanano_helpers.h> 42#include <google/protobuf/io/printer.h> 43#include <google/protobuf/wire_format.h> 44#include <google/protobuf/stubs/strutil.h> 45#include <google/protobuf/stubs/substitute.h> 46 47namespace google { 48namespace protobuf { 49namespace compiler { 50namespace javanano { 51 52using internal::WireFormat; 53using internal::WireFormatLite; 54 55namespace { 56 57const char* PrimitiveTypeName(JavaType type) { 58 switch (type) { 59 case JAVATYPE_INT : return "int"; 60 case JAVATYPE_LONG : return "long"; 61 case JAVATYPE_FLOAT : return "float"; 62 case JAVATYPE_DOUBLE : return "double"; 63 case JAVATYPE_BOOLEAN: return "boolean"; 64 case JAVATYPE_STRING : return "java.lang.String"; 65 case JAVATYPE_BYTES : return "byte[]"; 66 case JAVATYPE_ENUM : return NULL; 67 case JAVATYPE_MESSAGE: return NULL; 68 69 // No default because we want the compiler to complain if any new 70 // JavaTypes are added. 71 } 72 73 GOOGLE_LOG(FATAL) << "Can't get here."; 74 return NULL; 75} 76 77bool IsReferenceType(JavaType type) { 78 switch (type) { 79 case JAVATYPE_INT : return false; 80 case JAVATYPE_LONG : return false; 81 case JAVATYPE_FLOAT : return false; 82 case JAVATYPE_DOUBLE : return false; 83 case JAVATYPE_BOOLEAN: return false; 84 case JAVATYPE_STRING : return true; 85 case JAVATYPE_BYTES : return true; 86 case JAVATYPE_ENUM : return false; 87 case JAVATYPE_MESSAGE: return true; 88 89 // No default because we want the compiler to complain if any new 90 // JavaTypes are added. 91 } 92 93 GOOGLE_LOG(FATAL) << "Can't get here."; 94 return false; 95} 96 97bool IsArrayType(JavaType type) { 98 switch (type) { 99 case JAVATYPE_INT : return false; 100 case JAVATYPE_LONG : return false; 101 case JAVATYPE_FLOAT : return false; 102 case JAVATYPE_DOUBLE : return false; 103 case JAVATYPE_BOOLEAN: return false; 104 case JAVATYPE_STRING : return false; 105 case JAVATYPE_BYTES : return true; 106 case JAVATYPE_ENUM : return false; 107 case JAVATYPE_MESSAGE: return false; 108 109 // No default because we want the compiler to complain if any new 110 // JavaTypes are added. 111 } 112 113 GOOGLE_LOG(FATAL) << "Can't get here."; 114 return false; 115} 116 117const char* GetCapitalizedType(const FieldDescriptor* field) { 118 switch (field->type()) { 119 case FieldDescriptor::TYPE_INT32 : return "Int32" ; 120 case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; 121 case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; 122 case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; 123 case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; 124 case FieldDescriptor::TYPE_INT64 : return "Int64" ; 125 case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; 126 case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; 127 case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; 128 case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; 129 case FieldDescriptor::TYPE_FLOAT : return "Float" ; 130 case FieldDescriptor::TYPE_DOUBLE : return "Double" ; 131 case FieldDescriptor::TYPE_BOOL : return "Bool" ; 132 case FieldDescriptor::TYPE_STRING : return "String" ; 133 case FieldDescriptor::TYPE_BYTES : return "Bytes" ; 134 case FieldDescriptor::TYPE_ENUM : return "Enum" ; 135 case FieldDescriptor::TYPE_GROUP : return "Group" ; 136 case FieldDescriptor::TYPE_MESSAGE : return "Message" ; 137 138 // No default because we want the compiler to complain if any new 139 // types are added. 140 } 141 142 GOOGLE_LOG(FATAL) << "Can't get here."; 143 return NULL; 144} 145 146// For encodings with fixed sizes, returns that size in bytes. Otherwise 147// returns -1. 148int FixedSize(FieldDescriptor::Type type) { 149 switch (type) { 150 case FieldDescriptor::TYPE_INT32 : return -1; 151 case FieldDescriptor::TYPE_INT64 : return -1; 152 case FieldDescriptor::TYPE_UINT32 : return -1; 153 case FieldDescriptor::TYPE_UINT64 : return -1; 154 case FieldDescriptor::TYPE_SINT32 : return -1; 155 case FieldDescriptor::TYPE_SINT64 : return -1; 156 case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; 157 case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; 158 case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; 159 case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; 160 case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; 161 case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; 162 163 case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; 164 case FieldDescriptor::TYPE_ENUM : return -1; 165 166 case FieldDescriptor::TYPE_STRING : return -1; 167 case FieldDescriptor::TYPE_BYTES : return -1; 168 case FieldDescriptor::TYPE_GROUP : return -1; 169 case FieldDescriptor::TYPE_MESSAGE : return -1; 170 171 // No default because we want the compiler to complain if any new 172 // types are added. 173 } 174 GOOGLE_LOG(FATAL) << "Can't get here."; 175 return -1; 176} 177 178// Returns true if the field has a default value equal to NaN. 179bool IsDefaultNaN(const FieldDescriptor* field) { 180 switch (field->type()) { 181 case FieldDescriptor::TYPE_INT32 : return false; 182 case FieldDescriptor::TYPE_UINT32 : return false; 183 case FieldDescriptor::TYPE_SINT32 : return false; 184 case FieldDescriptor::TYPE_FIXED32 : return false; 185 case FieldDescriptor::TYPE_SFIXED32: return false; 186 case FieldDescriptor::TYPE_INT64 : return false; 187 case FieldDescriptor::TYPE_UINT64 : return false; 188 case FieldDescriptor::TYPE_SINT64 : return false; 189 case FieldDescriptor::TYPE_FIXED64 : return false; 190 case FieldDescriptor::TYPE_SFIXED64: return false; 191 case FieldDescriptor::TYPE_FLOAT : 192 return isnan(field->default_value_float()); 193 case FieldDescriptor::TYPE_DOUBLE : 194 return isnan(field->default_value_double()); 195 case FieldDescriptor::TYPE_BOOL : return false; 196 case FieldDescriptor::TYPE_STRING : return false; 197 case FieldDescriptor::TYPE_BYTES : return false; 198 case FieldDescriptor::TYPE_ENUM : return false; 199 case FieldDescriptor::TYPE_GROUP : return false; 200 case FieldDescriptor::TYPE_MESSAGE : return false; 201 202 // No default because we want the compiler to complain if any new 203 // types are added. 204 } 205 206 GOOGLE_LOG(FATAL) << "Can't get here."; 207 return false; 208} 209 210// Return true if the type is a that has variable length 211// for instance String's. 212bool IsVariableLenType(JavaType type) { 213 switch (type) { 214 case JAVATYPE_INT : return false; 215 case JAVATYPE_LONG : return false; 216 case JAVATYPE_FLOAT : return false; 217 case JAVATYPE_DOUBLE : return false; 218 case JAVATYPE_BOOLEAN: return false; 219 case JAVATYPE_STRING : return true; 220 case JAVATYPE_BYTES : return true; 221 case JAVATYPE_ENUM : return false; 222 case JAVATYPE_MESSAGE: return true; 223 224 // No default because we want the compiler to complain if any new 225 // JavaTypes are added. 226 } 227 228 GOOGLE_LOG(FATAL) << "Can't get here."; 229 return false; 230} 231 232bool AllAscii(const string& text) { 233 for (int i = 0; i < text.size(); i++) { 234 if ((text[i] & 0x80) != 0) { 235 return false; 236 } 237 } 238 return true; 239} 240 241void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params, 242 map<string, string>* variables) { 243 (*variables)["name"] = 244 RenameJavaKeywords(UnderscoresToCamelCase(descriptor)); 245 (*variables)["capitalized_name"] = 246 RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor)); 247 (*variables)["number"] = SimpleItoa(descriptor->number()); 248 (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); 249 (*variables)["default"] = DefaultValue(params, descriptor); 250 (*variables)["default_constant"] = FieldDefaultConstantName(descriptor); 251 // For C++-string types (string and bytes), we might need to have 252 // the generated code do the unicode decoding (see comments in 253 // InternalNano.java for gory details.). We would like to do this 254 // once into a "private static final" field and re-use that from 255 // then on. 256 if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING && 257 !descriptor->default_value_string().empty()) { 258 string default_value; 259 if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { 260 default_value = strings::Substitute( 261 "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")", 262 CEscape(descriptor->default_value_string())); 263 } else { 264 if (AllAscii(descriptor->default_value_string())) { 265 // All chars are ASCII. In this case CEscape() works fine. 266 default_value = "\"" + CEscape(descriptor->default_value_string()) + "\""; 267 } else { 268 default_value = strings::Substitute( 269 "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")", 270 CEscape(descriptor->default_value_string())); 271 } 272 } 273 (*variables)["default_constant_value"] = default_value; 274 } 275 (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); 276 (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); 277 (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); 278 (*variables)["tag_size"] = SimpleItoa( 279 WireFormat::TagSize(descriptor->number(), descriptor->type())); 280 if (IsReferenceType(GetJavaType(descriptor))) { 281 (*variables)["null_check"] = 282 " if (value == null) {\n" 283 " throw new NullPointerException();\n" 284 " }\n"; 285 } else { 286 (*variables)["null_check"] = ""; 287 } 288 int fixed_size = FixedSize(descriptor->type()); 289 if (fixed_size != -1) { 290 (*variables)["fixed_size"] = SimpleItoa(fixed_size); 291 } 292 (*variables)["message_name"] = descriptor->containing_type()->name(); 293 (*variables)["empty_array_name"] = EmptyArrayName(params, descriptor); 294} 295} // namespace 296 297// =================================================================== 298 299PrimitiveFieldGenerator:: 300PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) 301 : FieldGenerator(params), descriptor_(descriptor) { 302 SetPrimitiveVariables(descriptor, params, &variables_); 303} 304 305PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} 306 307void PrimitiveFieldGenerator:: 308GenerateMembers(io::Printer* printer) const { 309 if (variables_.find("default_constant_value") != variables_.end()) { 310 // Those primitive types that need a saved default. 311 printer->Print(variables_, 312 "private static final $type$ $default_constant$ = $default_constant_value$;\n"); 313 if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { 314 printer->Print(variables_, 315 "public $type$ $name$ = $default$.clone();\n"); 316 } else { 317 printer->Print(variables_, 318 "public $type$ $name$ = $default$;\n"); 319 } 320 } else { 321 printer->Print(variables_, 322 "public $type$ $name$ = $default$;\n"); 323 } 324 325 if (params_.generate_has()) { 326 printer->Print(variables_, 327 "public boolean has$capitalized_name$ = false;\n"); 328 } 329} 330 331void PrimitiveFieldGenerator:: 332GenerateParsingCode(io::Printer* printer) const { 333 printer->Print(variables_, 334 "this.$name$ = input.read$capitalized_type$();\n"); 335 336 if (params_.generate_has()) { 337 printer->Print(variables_, 338 "has$capitalized_name$ = true;\n"); 339 } 340} 341 342void PrimitiveFieldGenerator:: 343GenerateSerializationConditional(io::Printer* printer) const { 344 if (params_.generate_has()) { 345 printer->Print(variables_, 346 "if (has$capitalized_name$ || "); 347 } else { 348 printer->Print(variables_, 349 "if ("); 350 } 351 if (IsArrayType(GetJavaType(descriptor_))) { 352 printer->Print(variables_, 353 "!java.util.Arrays.equals(this.$name$, $default$)) {\n"); 354 } else if (IsReferenceType(GetJavaType(descriptor_))) { 355 printer->Print(variables_, 356 "!this.$name$.equals($default$)) {\n"); 357 } else if (IsDefaultNaN(descriptor_)) { 358 printer->Print(variables_, 359 "!$capitalized_type$.isNaN(this.$name$)) {\n"); 360 } else { 361 printer->Print(variables_, 362 "this.$name$ != $default$) {\n"); 363 } 364} 365 366void PrimitiveFieldGenerator:: 367GenerateSerializationCode(io::Printer* printer) const { 368 if (descriptor_->is_required()) { 369 printer->Print(variables_, 370 "output.write$capitalized_type$($number$, this.$name$);\n"); 371 } else { 372 GenerateSerializationConditional(printer); 373 printer->Print(variables_, 374 " output.write$capitalized_type$($number$, this.$name$);\n" 375 "}\n"); 376 } 377} 378 379void PrimitiveFieldGenerator:: 380GenerateSerializedSizeCode(io::Printer* printer) const { 381 if (descriptor_->is_required()) { 382 printer->Print(variables_, 383 "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 384 " .compute$capitalized_type$Size($number$, this.$name$);\n"); 385 } else { 386 GenerateSerializationConditional(printer); 387 printer->Print(variables_, 388 " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 389 " .compute$capitalized_type$Size($number$, this.$name$);\n" 390 "}\n"); 391 } 392} 393 394string PrimitiveFieldGenerator::GetBoxedType() const { 395 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); 396} 397 398// =================================================================== 399 400RepeatedPrimitiveFieldGenerator:: 401RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) 402 : FieldGenerator(params), descriptor_(descriptor) { 403 SetPrimitiveVariables(descriptor, params, &variables_); 404} 405 406RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} 407 408void RepeatedPrimitiveFieldGenerator:: 409GenerateMembers(io::Printer* printer) const { 410 printer->Print(variables_, 411 "public $type$[] $name$ = $default$;\n"); 412} 413 414void RepeatedPrimitiveFieldGenerator:: 415GenerateParsingCode(io::Printer* printer) const { 416 // First, figure out the length of the array, then parse. 417 if (descriptor_->options().packed()) { 418 printer->Print(variables_, 419 "int length = input.readRawVarint32();\n" 420 "int limit = input.pushLimit(length);\n" 421 "// First pass to compute array length.\n" 422 "int arrayLength = 0;\n" 423 "int startPos = input.getPosition();\n" 424 "while (input.getBytesUntilLimit() > 0) {\n" 425 " input.read$capitalized_type$();\n" 426 " arrayLength++;\n" 427 "}\n" 428 "input.rewindToPosition(startPos);\n" 429 "this.$name$ = new $type$[arrayLength];\n" 430 "for (int i = 0; i < arrayLength; i++) {\n" 431 " this.$name$[i] = input.read$capitalized_type$();\n" 432 "}\n" 433 "input.popLimit(limit);\n"); 434 } else { 435 printer->Print(variables_, 436 "int arrayLength = com.google.protobuf.nano.WireFormatNano.getRepeatedFieldArrayLength(input, $tag$);\n" 437 "int i = this.$name$.length;\n"); 438 439 if (GetJavaType(descriptor_) == JAVATYPE_BYTES) { 440 printer->Print(variables_, 441 "byte[][] newArray = new byte[i + arrayLength][];\n" 442 "System.arraycopy(this.$name$, 0, newArray, 0, i);\n" 443 "this.$name$ = newArray;\n"); 444 } else { 445 printer->Print(variables_, 446 "$type$[] newArray = new $type$[i + arrayLength];\n" 447 "System.arraycopy(this.$name$, 0, newArray, 0, i);\n" 448 "this.$name$ = newArray;\n"); 449 } 450 printer->Print(variables_, 451 "for (; i < this.$name$.length - 1; i++) {\n" 452 " this.$name$[i] = input.read$capitalized_type$();\n" 453 " input.readTag();\n" 454 "}\n" 455 "// Last one without readTag.\n" 456 "this.$name$[i] = input.read$capitalized_type$();\n"); 457 } 458} 459 460void RepeatedPrimitiveFieldGenerator:: 461GenerateRepeatedDataSizeCode(io::Printer* printer) const { 462 // Creates a variable dataSize and puts the serialized size in 463 // there. 464 if (FixedSize(descriptor_->type()) == -1) { 465 printer->Print(variables_, 466 "int dataSize = 0;\n" 467 "for ($type$ element : this.$name$) {\n" 468 " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 469 " .compute$capitalized_type$SizeNoTag(element);\n" 470 "}\n"); 471 } else { 472 printer->Print(variables_, 473 "int dataSize = $fixed_size$ * this.$name$.length;\n"); 474 } 475} 476 477void RepeatedPrimitiveFieldGenerator:: 478GenerateSerializationCode(io::Printer* printer) const { 479 if (descriptor_->options().packed()) { 480 printer->Print(variables_, 481 "if (this.$name$.length > 0) {\n"); 482 printer->Indent(); 483 GenerateRepeatedDataSizeCode(printer); 484 printer->Outdent(); 485 printer->Print(variables_, 486 " output.writeRawVarint32($tag$);\n" 487 " output.writeRawVarint32(dataSize);\n" 488 "}\n"); 489 printer->Print(variables_, 490 "for ($type$ element : this.$name$) {\n" 491 " output.write$capitalized_type$NoTag(element);\n" 492 "}\n"); 493 } else { 494 printer->Print(variables_, 495 "for ($type$ element : this.$name$) {\n" 496 " output.write$capitalized_type$($number$, element);\n" 497 "}\n"); 498 } 499} 500 501void RepeatedPrimitiveFieldGenerator:: 502GenerateSerializedSizeCode(io::Printer* printer) const { 503 printer->Print(variables_, 504 "if (this.$name$.length > 0) {\n"); 505 printer->Indent(); 506 507 GenerateRepeatedDataSizeCode(printer); 508 509 printer->Print( 510 "size += dataSize;\n"); 511 if (descriptor_->options().packed()) { 512 printer->Print(variables_, 513 "size += $tag_size$;\n" 514 "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" 515 " .computeRawVarint32Size(dataSize);\n"); 516 } else { 517 printer->Print(variables_, 518 "size += $tag_size$ * this.$name$.length;\n"); 519 } 520 521 printer->Outdent(); 522 523 printer->Print( 524 "}\n"); 525} 526 527string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { 528 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); 529} 530 531} // namespace javanano 532} // namespace compiler 533} // namespace protobuf 534} // namespace google 535