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 <algorithm> 36#include <google/protobuf/stubs/hash.h> 37#include <google/protobuf/compiler/javamicro/javamicro_message.h> 38#include <google/protobuf/compiler/javamicro/javamicro_enum.h> 39#include <google/protobuf/compiler/javamicro/javamicro_helpers.h> 40#include <google/protobuf/stubs/strutil.h> 41#include <google/protobuf/io/printer.h> 42#include <google/protobuf/io/coded_stream.h> 43#include <google/protobuf/wire_format.h> 44#include <google/protobuf/descriptor.pb.h> 45 46namespace google { 47namespace protobuf { 48namespace compiler { 49namespace javamicro { 50 51using internal::WireFormat; 52using internal::WireFormatLite; 53 54namespace { 55 56void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { 57 // Print the field's proto-syntax definition as a comment. We don't want to 58 // print group bodies so we cut off after the first line. 59 string def = field->DebugString(); 60 printer->Print("// $def$\n", 61 "def", def.substr(0, def.find_first_of('\n'))); 62} 63 64struct FieldOrderingByNumber { 65 inline bool operator()(const FieldDescriptor* a, 66 const FieldDescriptor* b) const { 67 return a->number() < b->number(); 68 } 69}; 70 71// Sort the fields of the given Descriptor by number into a new[]'d array 72// and return it. 73const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { 74 const FieldDescriptor** fields = 75 new const FieldDescriptor*[descriptor->field_count()]; 76 for (int i = 0; i < descriptor->field_count(); i++) { 77 fields[i] = descriptor->field(i); 78 } 79 sort(fields, fields + descriptor->field_count(), 80 FieldOrderingByNumber()); 81 return fields; 82} 83 84// Get an identifier that uniquely identifies this type within the file. 85// This is used to declare static variables related to this type at the 86// outermost file scope. 87string UniqueFileScopeIdentifier(const Descriptor* descriptor) { 88 return "static_" + StringReplace(descriptor->full_name(), ".", "_", true); 89} 90 91// Returns true if the message type has any required fields. If it doesn't, 92// we can optimize out calls to its isInitialized() method. 93// 94// already_seen is used to avoid checking the same type multiple times 95// (and also to protect against recursion). 96static bool HasRequiredFields( 97 const Descriptor* type, 98 hash_set<const Descriptor*>* already_seen) { 99 if (already_seen->count(type) > 0) { 100 // The type is already in cache. This means that either: 101 // a. The type has no required fields. 102 // b. We are in the midst of checking if the type has required fields, 103 // somewhere up the stack. In this case, we know that if the type 104 // has any required fields, they'll be found when we return to it, 105 // and the whole call to HasRequiredFields() will return true. 106 // Therefore, we don't have to check if this type has required fields 107 // here. 108 return false; 109 } 110 already_seen->insert(type); 111 112 // If the type has extensions, an extension with message type could contain 113 // required fields, so we have to be conservative and assume such an 114 // extension exists. 115 if (type->extension_range_count() > 0) return true; 116 117 for (int i = 0; i < type->field_count(); i++) { 118 const FieldDescriptor* field = type->field(i); 119 if (field->is_required()) { 120 return true; 121 } 122 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 123 if (HasRequiredFields(field->message_type(), already_seen)) { 124 return true; 125 } 126 } 127 } 128 129 return false; 130} 131 132static bool HasRequiredFields(const Descriptor* type) { 133 hash_set<const Descriptor*> already_seen; 134 return HasRequiredFields(type, &already_seen); 135} 136 137} // namespace 138 139// =================================================================== 140 141MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params) 142 : params_(params), 143 descriptor_(descriptor), 144 field_generators_(descriptor, params) { 145} 146 147MessageGenerator::~MessageGenerator() {} 148 149void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { 150 // Generate static members for all nested types. 151 for (int i = 0; i < descriptor_->nested_type_count(); i++) { 152 // TODO(kenton): Reuse MessageGenerator objects? 153 MessageGenerator(descriptor_->nested_type(i), params_) 154 .GenerateStaticVariables(printer); 155 } 156} 157 158void MessageGenerator::GenerateStaticVariableInitializers( 159 io::Printer* printer) { 160 // Generate static member initializers for all nested types. 161 for (int i = 0; i < descriptor_->nested_type_count(); i++) { 162 // TODO(kenton): Reuse MessageGenerator objects? 163 MessageGenerator(descriptor_->nested_type(i), params_) 164 .GenerateStaticVariableInitializers(printer); 165 } 166 167 if (descriptor_->extension_count() != 0) { 168 GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; 169 } 170} 171 172void MessageGenerator::Generate(io::Printer* printer) { 173 const string& file_name = descriptor_->file()->name(); 174 bool is_own_file = 175 params_.java_multiple_files(file_name) 176 && descriptor_->containing_type() == NULL; 177 178 if ((descriptor_->extension_count() != 0) 179 || (descriptor_->extension_range_count() != 0)) { 180 GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; 181 } 182 183 // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in 184 // the inner or outer class. This causes Java warnings, but is not fatal, so we suppress those 185 // warnings here in the class declaration. 186 printer->Print( 187 "@SuppressWarnings(\"hiding\")\n" 188 "public $modifiers$ final class $classname$ extends\n" 189 " com.google.protobuf.micro.MessageMicro {\n", 190 "modifiers", is_own_file ? "" : "static", 191 "classname", descriptor_->name()); 192 printer->Indent(); 193 printer->Print( 194 "public $classname$() {}\n" 195 "\n", 196 "classname", descriptor_->name()); 197 198 // Nested types and extensions 199 for (int i = 0; i < descriptor_->enum_type_count(); i++) { 200 EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer); 201 } 202 203 for (int i = 0; i < descriptor_->nested_type_count(); i++) { 204 MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer); 205 } 206 207 // Fields 208 for (int i = 0; i < descriptor_->field_count(); i++) { 209 PrintFieldComment(printer, descriptor_->field(i)); 210 printer->Print("public static final int $constant_name$ = $number$;\n", 211 "constant_name", FieldConstantName(descriptor_->field(i)), 212 "number", SimpleItoa(descriptor_->field(i)->number())); 213 field_generators_.get(descriptor_->field(i)).GenerateMembers(printer); 214 printer->Print("\n"); 215 } 216 217 GenerateClear(printer); 218 GenerateIsInitialized(printer); 219 GenerateMessageSerializationMethods(printer); 220 GenerateMergeFromMethods(printer); 221 GenerateParseFromMethods(printer); 222 223 printer->Outdent(); 224 printer->Print("}\n\n"); 225} 226 227// =================================================================== 228 229void MessageGenerator:: 230GenerateMessageSerializationMethods(io::Printer* printer) { 231 scoped_array<const FieldDescriptor*> sorted_fields( 232 SortFieldsByNumber(descriptor_)); 233 234 if (descriptor_->extension_range_count() != 0) { 235 GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; 236 } 237 238 // writeTo only throws an exception if it contains one or more fields to write 239 if (descriptor_->field_count() > 0) { 240 printer->Print( 241 "@Override\n" 242 "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n" 243 " throws java.io.IOException {\n"); 244 } else { 245 printer->Print( 246 "@Override\n" 247 "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output) {\n"); 248 } 249 printer->Indent(); 250 251 // Output the fields in sorted order 252 for (int i = 0; i < descriptor_->field_count(); i++) { 253 GenerateSerializeOneField(printer, sorted_fields[i]); 254 } 255 256 printer->Outdent(); 257 printer->Print( 258 "}\n" 259 "\n" 260 "private int cachedSize = -1;\n" 261 "@Override\n" 262 "public int getCachedSize() {\n" 263 " if (cachedSize < 0) {\n" 264 " // getSerializedSize sets cachedSize\n" 265 " getSerializedSize();\n" 266 " }\n" 267 " return cachedSize;\n" 268 "}\n" 269 "\n" 270 "@Override\n" 271 "public int getSerializedSize() {\n" 272 " int size = 0;\n"); 273 printer->Indent(); 274 275 for (int i = 0; i < descriptor_->field_count(); i++) { 276 field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); 277 } 278 279 printer->Outdent(); 280 printer->Print( 281 " cachedSize = size;\n" 282 " return size;\n" 283 "}\n" 284 "\n"); 285} 286 287void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) { 288 scoped_array<const FieldDescriptor*> sorted_fields( 289 SortFieldsByNumber(descriptor_)); 290 291 if (params_.java_use_vector()) { 292 printer->Print( 293 "@Override\n" 294 "public com.google.protobuf.micro.MessageMicro mergeFrom(\n" 295 " com.google.protobuf.micro.CodedInputStreamMicro input)\n" 296 " throws java.io.IOException {\n", 297 "classname", descriptor_->name()); 298 } else { 299 printer->Print( 300 "@Override\n" 301 "public $classname$ mergeFrom(\n" 302 " com.google.protobuf.micro.CodedInputStreamMicro input)\n" 303 " throws java.io.IOException {\n", 304 "classname", descriptor_->name()); 305 } 306 printer->Indent(); 307 308 printer->Print( 309 "while (true) {\n"); 310 printer->Indent(); 311 312 printer->Print( 313 "int tag = input.readTag();\n" 314 "switch (tag) {\n"); 315 printer->Indent(); 316 317 printer->Print( 318 "case 0:\n" // zero signals EOF / limit reached 319 " return this;\n" 320 "default: {\n" 321 " if (!parseUnknownField(input, tag)) {\n" 322 " return this;\n" // it's an endgroup tag 323 " }\n" 324 " break;\n" 325 "}\n"); 326 327 for (int i = 0; i < descriptor_->field_count(); i++) { 328 const FieldDescriptor* field = sorted_fields[i]; 329 uint32 tag = WireFormatLite::MakeTag(field->number(), 330 WireFormat::WireTypeForField(field)); 331 332 printer->Print( 333 "case $tag$: {\n", 334 "tag", SimpleItoa(tag)); 335 printer->Indent(); 336 337 field_generators_.get(field).GenerateParsingCode(printer); 338 339 printer->Outdent(); 340 printer->Print( 341 " break;\n" 342 "}\n"); 343 } 344 345 printer->Outdent(); 346 printer->Outdent(); 347 printer->Outdent(); 348 printer->Print( 349 " }\n" // switch (tag) 350 " }\n" // while (true) 351 "}\n" 352 "\n"); 353} 354 355void MessageGenerator:: 356GenerateParseFromMethods(io::Printer* printer) { 357 // Note: These are separate from GenerateMessageSerializationMethods() 358 // because they need to be generated even for messages that are optimized 359 // for code size. 360 printer->Print( 361 "public static $classname$ parseFrom(byte[] data)\n" 362 " throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n" 363 " return ($classname$) (new $classname$().mergeFrom(data));\n" 364 "}\n" 365 "\n" 366 "public static $classname$ parseFrom(\n" 367 " com.google.protobuf.micro.CodedInputStreamMicro input)\n" 368 " throws java.io.IOException {\n" 369 " return new $classname$().mergeFrom(input);\n" 370 "}\n" 371 "\n", 372 "classname", descriptor_->name()); 373} 374 375void MessageGenerator::GenerateSerializeOneField( 376 io::Printer* printer, const FieldDescriptor* field) { 377 field_generators_.get(field).GenerateSerializationCode(printer); 378} 379 380void MessageGenerator::GenerateClear(io::Printer* printer) { 381 printer->Print( 382 "public final $classname$ clear() {\n", 383 "classname", descriptor_->name()); 384 printer->Indent(); 385 386 // Call clear for all of the fields. 387 for (int i = 0; i < descriptor_->field_count(); i++) { 388 const FieldDescriptor* field = descriptor_->field(i); 389 390 printer->Print( 391 "clear$name$();\n", 392 "name", UnderscoresToCapitalizedCamelCase(field)); 393 } 394 395 printer->Outdent(); 396 printer->Print( 397 " cachedSize = -1;\n" 398 " return this;\n" 399 "}\n" 400 "\n"); 401} 402 403 404void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { 405 printer->Print( 406 "public final boolean isInitialized() {\n"); 407 printer->Indent(); 408 409 // Check that all required fields in this message are set. 410 // TODO(kenton): We can optimize this when we switch to putting all the 411 // "has" fields into a single bitfield. 412 for (int i = 0; i < descriptor_->field_count(); i++) { 413 const FieldDescriptor* field = descriptor_->field(i); 414 415 if (field->is_required()) { 416 printer->Print( 417 "if (!has$name$) return false;\n", 418 "name", UnderscoresToCapitalizedCamelCase(field)); 419 } 420 } 421 422 // Now check that all embedded messages are initialized. 423 for (int i = 0; i < descriptor_->field_count(); i++) { 424 const FieldDescriptor* field = descriptor_->field(i); 425 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && 426 HasRequiredFields(field->message_type())) { 427 switch (field->label()) { 428 case FieldDescriptor::LABEL_REQUIRED: 429 printer->Print( 430 "if (!get$name$().isInitialized()) return false;\n", 431 "type", ClassName(params_, field->message_type()), 432 "name", UnderscoresToCapitalizedCamelCase(field)); 433 break; 434 case FieldDescriptor::LABEL_OPTIONAL: 435 printer->Print( 436 "if (has$name$()) {\n" 437 " if (!get$name$().isInitialized()) return false;\n" 438 "}\n", 439 "type", ClassName(params_, field->message_type()), 440 "name", UnderscoresToCapitalizedCamelCase(field)); 441 break; 442 case FieldDescriptor::LABEL_REPEATED: 443 if (params_.java_use_vector()) { 444 printer->Print( 445 "for (int i = 0; i < get$name$List().size(); i++) {\n" 446 " if (get$name$(i).isInitialized()) return false;\n" 447 "}\n", 448 "type", ClassName(params_, field->message_type()), 449 "name", UnderscoresToCapitalizedCamelCase(field)); 450 } else { 451 printer->Print( 452 "for ($type$ element : get$name$List()) {\n" 453 " if (!element.isInitialized()) return false;\n" 454 "}\n", 455 "type", ClassName(params_, field->message_type()), 456 "name", UnderscoresToCapitalizedCamelCase(field)); 457 } 458 break; 459 } 460 } 461 } 462 463 if (descriptor_->extension_range_count() > 0) { 464 printer->Print( 465 "if (!extensionsAreInitialized()) return false;\n"); 466 } 467 468 printer->Outdent(); 469 printer->Print( 470 " return true;\n" 471 "}\n" 472 "\n"); 473} 474 475// =================================================================== 476 477} // namespace javamicro 478} // namespace compiler 479} // namespace protobuf 480} // namespace google 481