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 bool is_own_file = 174 params_.java_multiple_files() || ((descriptor_->containing_type() == NULL) 175 && !params_.has_java_outer_classname(descriptor_->file()->name())); 176 177#if 0 178 GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file; 179 GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null"); 180 GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files(); 181 GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name()); 182#endif 183 184 if ((descriptor_->extension_count() != 0) 185 || (descriptor_->extension_range_count() != 0)) { 186 GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; 187 } 188 189 printer->Print( 190 "public $modifiers$ final class $classname$ extends\n" 191 " com.google.protobuf.micro.MessageMicro {\n", 192 "modifiers", is_own_file ? "" : "static", 193 "classname", descriptor_->name()); 194 printer->Indent(); 195 printer->Print( 196 "public $classname$() {}\n" 197 "\n", 198 "classname", descriptor_->name()); 199 200 // Nested types and extensions 201 for (int i = 0; i < descriptor_->enum_type_count(); i++) { 202 EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer); 203 } 204 205 for (int i = 0; i < descriptor_->nested_type_count(); i++) { 206 MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer); 207 } 208 209 // Fields 210 for (int i = 0; i < descriptor_->field_count(); i++) { 211 PrintFieldComment(printer, descriptor_->field(i)); 212 printer->Print("public static final int $constant_name$ = $number$;\n", 213 "constant_name", FieldConstantName(descriptor_->field(i)), 214 "number", SimpleItoa(descriptor_->field(i)->number())); 215 field_generators_.get(descriptor_->field(i)).GenerateMembers(printer); 216 printer->Print("\n"); 217 } 218 219 GenerateClear(printer); 220 GenerateIsInitialized(printer); 221 GenerateMessageSerializationMethods(printer); 222 GenerateMergeFromMethods(printer); 223 GenerateParseFromMethods(printer); 224 225 printer->Outdent(); 226 printer->Print("}\n\n"); 227} 228 229// =================================================================== 230 231void MessageGenerator:: 232GenerateMessageSerializationMethods(io::Printer* printer) { 233 scoped_array<const FieldDescriptor*> sorted_fields( 234 SortFieldsByNumber(descriptor_)); 235 236 if (descriptor_->extension_range_count() != 0) { 237 GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n"; 238 } 239 240 printer->Print( 241 "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n" 242 " throws java.io.IOException {\n"); 243 printer->Indent(); 244 245 // Output the fields in sorted order 246 for (int i = 0; i < descriptor_->field_count(); i++) { 247 GenerateSerializeOneField(printer, sorted_fields[i]); 248 } 249 250 printer->Outdent(); 251 printer->Print( 252 "}\n" 253 "\n" 254 "private int cachedSize = -1;\n" 255 "public int getCachedSize() {\n" 256 " if (cachedSize < 0) {\n" 257 " // getSerializedSize sets cachedSize\n" 258 " getSerializedSize();\n" 259 " }\n" 260 " return cachedSize;\n" 261 "}\n" 262 "\n" 263 "public int getSerializedSize() {\n" 264 " int size = 0;\n"); 265 printer->Indent(); 266 267 for (int i = 0; i < descriptor_->field_count(); i++) { 268 field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); 269 } 270 271 printer->Outdent(); 272 printer->Print( 273 " cachedSize = size;\n" 274 " return size;\n" 275 "}\n" 276 "\n"); 277} 278 279void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) { 280 scoped_array<const FieldDescriptor*> sorted_fields( 281 SortFieldsByNumber(descriptor_)); 282 283 if (params_.java_use_vector()) { 284 printer->Print( 285 "public com.google.protobuf.micro.MessageMicro mergeFrom(\n" 286 " com.google.protobuf.micro.CodedInputStreamMicro input)\n" 287 " throws java.io.IOException {\n", 288 "classname", descriptor_->name()); 289 } else { 290 printer->Print( 291 "public $classname$ mergeFrom(\n" 292 " com.google.protobuf.micro.CodedInputStreamMicro input)\n" 293 " throws java.io.IOException {\n", 294 "classname", descriptor_->name()); 295 } 296 printer->Indent(); 297 298 printer->Print( 299 "while (true) {\n"); 300 printer->Indent(); 301 302 printer->Print( 303 "int tag = input.readTag();\n" 304 "switch (tag) {\n"); 305 printer->Indent(); 306 307 printer->Print( 308 "case 0:\n" // zero signals EOF / limit reached 309 " return this;\n" 310 "default: {\n" 311 " if (!parseUnknownField(input, tag)) {\n" 312 " return this;\n" // it's an endgroup tag 313 " }\n" 314 " break;\n" 315 "}\n"); 316 317 for (int i = 0; i < descriptor_->field_count(); i++) { 318 const FieldDescriptor* field = sorted_fields[i]; 319 uint32 tag = WireFormatLite::MakeTag(field->number(), 320 WireFormat::WireTypeForField(field)); 321 322 printer->Print( 323 "case $tag$: {\n", 324 "tag", SimpleItoa(tag)); 325 printer->Indent(); 326 327 field_generators_.get(field).GenerateParsingCode(printer); 328 329 printer->Outdent(); 330 printer->Print( 331 " break;\n" 332 "}\n"); 333 } 334 335 printer->Outdent(); 336 printer->Outdent(); 337 printer->Outdent(); 338 printer->Print( 339 " }\n" // switch (tag) 340 " }\n" // while (true) 341 "}\n" 342 "\n"); 343} 344 345void MessageGenerator:: 346GenerateParseFromMethods(io::Printer* printer) { 347 bool is_own_file = 348 descriptor_->containing_type() == NULL; 349 350 // Note: These are separate from GenerateMessageSerializationMethods() 351 // because they need to be generated even for messages that are optimized 352 // for code size. 353 printer->Print( 354 "public $static$ $classname$ parseFrom(byte[] data)\n" 355 " throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n" 356 " return ($classname$) (new $classname$().mergeFrom(data));\n" 357 "}\n" 358 "\n" 359 "public $static$ $classname$ parseFrom(\n" 360 " com.google.protobuf.micro.CodedInputStreamMicro input)\n" 361 " throws java.io.IOException {\n" 362 " return ($classname$) (new $classname$().mergeFrom(input));\n" 363 "}\n" 364 "\n", 365 "static", (is_own_file ? "static" : ""), 366 "classname", descriptor_->name()); 367} 368 369void MessageGenerator::GenerateSerializeOneField( 370 io::Printer* printer, const FieldDescriptor* field) { 371 field_generators_.get(field).GenerateSerializationCode(printer); 372} 373 374void MessageGenerator::GenerateClear(io::Printer* printer) { 375 printer->Print( 376 "public final $classname$ clear() {\n", 377 "classname", descriptor_->name()); 378 printer->Indent(); 379 380 // Call clear for all of the fields. 381 for (int i = 0; i < descriptor_->field_count(); i++) { 382 const FieldDescriptor* field = descriptor_->field(i); 383 384 printer->Print( 385 "clear$name$();\n", 386 "name", UnderscoresToCapitalizedCamelCase(field)); 387 } 388 389 printer->Outdent(); 390 printer->Print( 391 " cachedSize = -1;\n" 392 " return this;\n" 393 "}\n" 394 "\n"); 395} 396 397 398void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { 399 printer->Print( 400 "public final boolean isInitialized() {\n"); 401 printer->Indent(); 402 403 // Check that all required fields in this message are set. 404 // TODO(kenton): We can optimize this when we switch to putting all the 405 // "has" fields into a single bitfield. 406 for (int i = 0; i < descriptor_->field_count(); i++) { 407 const FieldDescriptor* field = descriptor_->field(i); 408 409 if (field->is_required()) { 410 printer->Print( 411 "if (!has$name$) return false;\n", 412 "name", UnderscoresToCapitalizedCamelCase(field)); 413 } 414 } 415 416 // Now check that all embedded messages are initialized. 417 for (int i = 0; i < descriptor_->field_count(); i++) { 418 const FieldDescriptor* field = descriptor_->field(i); 419 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && 420 HasRequiredFields(field->message_type())) { 421 switch (field->label()) { 422 case FieldDescriptor::LABEL_REQUIRED: 423 printer->Print( 424 "if (!get$name$().isInitialized()) return false;\n", 425 "type", ClassName(params_, field->message_type()), 426 "name", UnderscoresToCapitalizedCamelCase(field)); 427 break; 428 case FieldDescriptor::LABEL_OPTIONAL: 429 printer->Print( 430 "if (has$name$()) {\n" 431 " if (!get$name$().isInitialized()) return false;\n" 432 "}\n", 433 "type", ClassName(params_, field->message_type()), 434 "name", UnderscoresToCapitalizedCamelCase(field)); 435 break; 436 case FieldDescriptor::LABEL_REPEATED: 437 if (params_.java_use_vector()) { 438 printer->Print( 439 "for (int i = 0; i < get$name$List().size(); i++) {\n" 440 " if (get$name$(i).isInitialized()) return false;\n" 441 "}\n", 442 "type", ClassName(params_, field->message_type()), 443 "name", UnderscoresToCapitalizedCamelCase(field)); 444 } else { 445 printer->Print( 446 "for ($type$ element : get$name$List()) {\n" 447 " if (!element.isInitialized()) return false;\n" 448 "}\n", 449 "type", ClassName(params_, field->message_type()), 450 "name", UnderscoresToCapitalizedCamelCase(field)); 451 } 452 break; 453 } 454 } 455 } 456 457 if (descriptor_->extension_range_count() > 0) { 458 printer->Print( 459 "if (!extensionsAreInitialized()) return false;\n"); 460 } 461 462 printer->Outdent(); 463 printer->Print( 464 " return true;\n" 465 "}\n" 466 "\n"); 467} 468 469// =================================================================== 470 471} // namespace javamicro 472} // namespace compiler 473} // namespace protobuf 474} // namespace google 475