1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 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 #include <algorithm> 32 #include <iostream> 33 #include <sstream> 34 35 #include <google/protobuf/stubs/hash.h> 36 #include <google/protobuf/compiler/objectivec/objectivec_message.h> 37 #include <google/protobuf/compiler/objectivec/objectivec_enum.h> 38 #include <google/protobuf/compiler/objectivec/objectivec_extension.h> 39 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h> 40 #include <google/protobuf/stubs/stl_util.h> 41 #include <google/protobuf/stubs/strutil.h> 42 #include <google/protobuf/io/printer.h> 43 #include <google/protobuf/io/coded_stream.h> 44 #include <google/protobuf/io/zero_copy_stream_impl.h> 45 #include <google/protobuf/wire_format.h> 46 #include <google/protobuf/wire_format_lite_inl.h> 47 #include <google/protobuf/descriptor.pb.h> 48 49 namespace google { 50 namespace protobuf { 51 namespace compiler { 52 namespace objectivec { 53 54 using internal::WireFormat; 55 using internal::WireFormatLite; 56 57 namespace { 58 struct FieldOrderingByNumber { 59 inline bool operator()(const FieldDescriptor* a, 60 const FieldDescriptor* b) const { 61 return a->number() < b->number(); 62 } 63 }; 64 65 int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { 66 // The first item in the object structure is our uint32[] for has bits. 67 // We then want to order things to make the instances as small as 68 // possible. So we follow the has bits with: 69 // 1. Anything always 4 bytes - float, *32, enums 70 // 2. Anything that is always a pointer (they will be 8 bytes on 64 bit 71 // builds and 4 bytes on 32bit builds. 72 // 3. Anything always 8 bytes - double, *64 73 // 74 // NOTE: Bools aren't listed, they were stored in the has bits. 75 // 76 // Why? Using 64bit builds as an example, this means worse case, we have 77 // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes 78 // are wasted before the 4 byte values. Then if we have an odd number of 79 // those 4 byte values, the 8 byte values will be pushed down by 32bits to 80 // keep them aligned. But the structure will end 8 byte aligned, so no 81 // waste on the end. If you did the reverse order, you could waste 4 bytes 82 // before the first 8 byte value (after the has array), then a single 83 // bool on the end would need 7 bytes of padding to make the overall 84 // structure 8 byte aligned; so 11 bytes, wasted total. 85 86 // Anything repeated is a GPB*Array/NSArray, so pointer. 87 if (descriptor->is_repeated()) { 88 return 3; 89 } 90 91 switch (descriptor->type()) { 92 // All always 8 bytes. 93 case FieldDescriptor::TYPE_DOUBLE: 94 case FieldDescriptor::TYPE_INT64: 95 case FieldDescriptor::TYPE_SINT64: 96 case FieldDescriptor::TYPE_UINT64: 97 case FieldDescriptor::TYPE_SFIXED64: 98 case FieldDescriptor::TYPE_FIXED64: 99 return 4; 100 101 // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes 102 // depending on the build architecture. 103 case FieldDescriptor::TYPE_GROUP: 104 case FieldDescriptor::TYPE_MESSAGE: 105 case FieldDescriptor::TYPE_STRING: 106 case FieldDescriptor::TYPE_BYTES: 107 return 3; 108 109 // All always 4 bytes (enums are int32s). 110 case FieldDescriptor::TYPE_FLOAT: 111 case FieldDescriptor::TYPE_INT32: 112 case FieldDescriptor::TYPE_SINT32: 113 case FieldDescriptor::TYPE_UINT32: 114 case FieldDescriptor::TYPE_SFIXED32: 115 case FieldDescriptor::TYPE_FIXED32: 116 case FieldDescriptor::TYPE_ENUM: 117 return 2; 118 119 // 0 bytes. Stored in the has bits. 120 case FieldDescriptor::TYPE_BOOL: 121 return 99; // End of the list (doesn't really matter). 122 } 123 124 // Some compilers report reaching end of function even though all cases of 125 // the enum are handed in the switch. 126 GOOGLE_LOG(FATAL) << "Can't get here."; 127 return 0; 128 } 129 130 struct FieldOrderingByStorageSize { 131 inline bool operator()(const FieldDescriptor* a, 132 const FieldDescriptor* b) const { 133 // Order by grouping. 134 const int order_group_a = OrderGroupForFieldDescriptor(a); 135 const int order_group_b = OrderGroupForFieldDescriptor(b); 136 if (order_group_a != order_group_b) { 137 return order_group_a < order_group_b; 138 } 139 // Within the group, order by field number (provides stable ordering). 140 return a->number() < b->number(); 141 } 142 }; 143 144 struct ExtensionRangeOrdering { 145 bool operator()(const Descriptor::ExtensionRange* a, 146 const Descriptor::ExtensionRange* b) const { 147 return a->start < b->start; 148 } 149 }; 150 151 // Sort the fields of the given Descriptor by number into a new[]'d array 152 // and return it. 153 const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { 154 const FieldDescriptor** fields = 155 new const FieldDescriptor* [descriptor->field_count()]; 156 for (int i = 0; i < descriptor->field_count(); i++) { 157 fields[i] = descriptor->field(i); 158 } 159 sort(fields, fields + descriptor->field_count(), FieldOrderingByNumber()); 160 return fields; 161 } 162 163 // Sort the fields of the given Descriptor by storage size into a new[]'d 164 // array and return it. 165 const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) { 166 const FieldDescriptor** fields = 167 new const FieldDescriptor* [descriptor->field_count()]; 168 for (int i = 0; i < descriptor->field_count(); i++) { 169 fields[i] = descriptor->field(i); 170 } 171 sort(fields, fields + descriptor->field_count(), 172 FieldOrderingByStorageSize()); 173 return fields; 174 } 175 } // namespace 176 177 MessageGenerator::MessageGenerator(const string& root_classname, 178 const Descriptor* descriptor, 179 const Options& options) 180 : root_classname_(root_classname), 181 descriptor_(descriptor), 182 field_generators_(descriptor, options), 183 class_name_(ClassName(descriptor_)) { 184 for (int i = 0; i < descriptor_->extension_count(); i++) { 185 extension_generators_.push_back( 186 new ExtensionGenerator(class_name_, descriptor_->extension(i))); 187 } 188 189 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { 190 OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i)); 191 oneof_generators_.push_back(generator); 192 } 193 194 for (int i = 0; i < descriptor_->enum_type_count(); i++) { 195 EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i)); 196 enum_generators_.push_back(generator); 197 } 198 199 for (int i = 0; i < descriptor_->nested_type_count(); i++) { 200 MessageGenerator* generator = 201 new MessageGenerator(root_classname_, 202 descriptor_->nested_type(i), 203 options); 204 nested_message_generators_.push_back(generator); 205 } 206 } 207 208 MessageGenerator::~MessageGenerator() { 209 STLDeleteContainerPointers(extension_generators_.begin(), 210 extension_generators_.end()); 211 STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end()); 212 STLDeleteContainerPointers(nested_message_generators_.begin(), 213 nested_message_generators_.end()); 214 STLDeleteContainerPointers(oneof_generators_.begin(), 215 oneof_generators_.end()); 216 } 217 218 void MessageGenerator::GenerateStaticVariablesInitialization( 219 io::Printer* printer) { 220 for (vector<ExtensionGenerator*>::iterator iter = 221 extension_generators_.begin(); 222 iter != extension_generators_.end(); ++iter) { 223 (*iter)->GenerateStaticVariablesInitialization(printer); 224 } 225 226 for (vector<MessageGenerator*>::iterator iter = 227 nested_message_generators_.begin(); 228 iter != nested_message_generators_.end(); ++iter) { 229 (*iter)->GenerateStaticVariablesInitialization(printer); 230 } 231 } 232 233 void MessageGenerator::DetermineForwardDeclarations(set<string>* fwd_decls) { 234 if (!IsMapEntryMessage(descriptor_)) { 235 for (int i = 0; i < descriptor_->field_count(); i++) { 236 const FieldDescriptor* fieldDescriptor = descriptor_->field(i); 237 field_generators_.get(fieldDescriptor) 238 .DetermineForwardDeclarations(fwd_decls); 239 } 240 } 241 242 for (vector<MessageGenerator*>::iterator iter = 243 nested_message_generators_.begin(); 244 iter != nested_message_generators_.end(); ++iter) { 245 (*iter)->DetermineForwardDeclarations(fwd_decls); 246 } 247 } 248 249 void MessageGenerator::GenerateEnumHeader(io::Printer* printer) { 250 for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin(); 251 iter != enum_generators_.end(); ++iter) { 252 (*iter)->GenerateHeader(printer); 253 } 254 255 for (vector<MessageGenerator*>::iterator iter = 256 nested_message_generators_.begin(); 257 iter != nested_message_generators_.end(); ++iter) { 258 (*iter)->GenerateEnumHeader(printer); 259 } 260 } 261 262 void MessageGenerator::GenerateExtensionRegistrationSource( 263 io::Printer* printer) { 264 for (vector<ExtensionGenerator*>::iterator iter = 265 extension_generators_.begin(); 266 iter != extension_generators_.end(); ++iter) { 267 (*iter)->GenerateRegistrationSource(printer); 268 } 269 270 for (vector<MessageGenerator*>::iterator iter = 271 nested_message_generators_.begin(); 272 iter != nested_message_generators_.end(); ++iter) { 273 (*iter)->GenerateExtensionRegistrationSource(printer); 274 } 275 } 276 277 void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { 278 // This a a map entry message, just recurse and do nothing directly. 279 if (IsMapEntryMessage(descriptor_)) { 280 for (vector<MessageGenerator*>::iterator iter = 281 nested_message_generators_.begin(); 282 iter != nested_message_generators_.end(); ++iter) { 283 (*iter)->GenerateMessageHeader(printer); 284 } 285 return; 286 } 287 288 printer->Print( 289 "#pragma mark - $classname$\n" 290 "\n", 291 "classname", class_name_); 292 293 if (descriptor_->field_count()) { 294 scoped_array<const FieldDescriptor*> sorted_fields( 295 SortFieldsByNumber(descriptor_)); 296 297 printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n", 298 "classname", class_name_); 299 printer->Indent(); 300 301 for (int i = 0; i < descriptor_->field_count(); i++) { 302 field_generators_.get(sorted_fields[i]) 303 .GenerateFieldNumberConstant(printer); 304 } 305 306 printer->Outdent(); 307 printer->Print("};\n\n"); 308 } 309 310 for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); 311 iter != oneof_generators_.end(); ++iter) { 312 (*iter)->GenerateCaseEnum(printer); 313 } 314 315 string message_comments; 316 SourceLocation location; 317 if (descriptor_->GetSourceLocation(&location)) { 318 message_comments = BuildCommentsString(location); 319 } else { 320 message_comments = ""; 321 } 322 323 printer->Print( 324 "$comments$$deprecated_attribute$@interface $classname$ : GPBMessage\n\n", 325 "classname", class_name_, 326 "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, false, true), 327 "comments", message_comments); 328 329 vector<char> seen_oneofs(descriptor_->oneof_decl_count(), 0); 330 for (int i = 0; i < descriptor_->field_count(); i++) { 331 const FieldDescriptor* field = descriptor_->field(i); 332 if (field->containing_oneof() != NULL) { 333 const int oneof_index = field->containing_oneof()->index(); 334 if (!seen_oneofs[oneof_index]) { 335 seen_oneofs[oneof_index] = 1; 336 oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration( 337 printer); 338 } 339 } 340 field_generators_.get(field).GeneratePropertyDeclaration(printer); 341 } 342 343 printer->Print("@end\n\n"); 344 345 for (int i = 0; i < descriptor_->field_count(); i++) { 346 field_generators_.get(descriptor_->field(i)) 347 .GenerateCFunctionDeclarations(printer); 348 } 349 350 if (!oneof_generators_.empty()) { 351 for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); 352 iter != oneof_generators_.end(); ++iter) { 353 (*iter)->GenerateClearFunctionDeclaration(printer); 354 } 355 printer->Print("\n"); 356 } 357 358 if (descriptor_->extension_count() > 0) { 359 printer->Print("@interface $classname$ (DynamicMethods)\n\n", 360 "classname", class_name_); 361 for (vector<ExtensionGenerator*>::iterator iter = 362 extension_generators_.begin(); 363 iter != extension_generators_.end(); ++iter) { 364 (*iter)->GenerateMembersHeader(printer); 365 } 366 printer->Print("@end\n\n"); 367 } 368 369 for (vector<MessageGenerator*>::iterator iter = 370 nested_message_generators_.begin(); 371 iter != nested_message_generators_.end(); ++iter) { 372 (*iter)->GenerateMessageHeader(printer); 373 } 374 } 375 376 void MessageGenerator::GenerateSource(io::Printer* printer) { 377 if (!IsMapEntryMessage(descriptor_)) { 378 printer->Print( 379 "#pragma mark - $classname$\n" 380 "\n", 381 "classname", class_name_); 382 383 printer->Print("@implementation $classname$\n\n", 384 "classname", class_name_); 385 386 for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); 387 iter != oneof_generators_.end(); ++iter) { 388 (*iter)->GeneratePropertyImplementation(printer); 389 } 390 391 for (int i = 0; i < descriptor_->field_count(); i++) { 392 field_generators_.get(descriptor_->field(i)) 393 .GeneratePropertyImplementation(printer); 394 } 395 396 scoped_array<const FieldDescriptor*> sorted_fields( 397 SortFieldsByNumber(descriptor_)); 398 scoped_array<const FieldDescriptor*> size_order_fields( 399 SortFieldsByStorageSize(descriptor_)); 400 401 vector<const Descriptor::ExtensionRange*> sorted_extensions; 402 for (int i = 0; i < descriptor_->extension_range_count(); ++i) { 403 sorted_extensions.push_back(descriptor_->extension_range(i)); 404 } 405 406 sort(sorted_extensions.begin(), sorted_extensions.end(), 407 ExtensionRangeOrdering()); 408 409 // Assign has bits: 410 // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing 411 // who needs has bits and assigning them. 412 // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative 413 // index that groups all the elements in the oneof. 414 size_t num_has_bits = field_generators_.CalculateHasBits(); 415 size_t sizeof_has_storage = (num_has_bits + 31) / 32; 416 if (sizeof_has_storage == 0) { 417 // In the case where no field needs has bits, don't let the _has_storage_ 418 // end up as zero length (zero length arrays are sort of a grey area 419 // since it has to be at the start of the struct). This also ensures a 420 // field with only oneofs keeps the required negative indices they need. 421 sizeof_has_storage = 1; 422 } 423 // Tell all the fields the oneof base. 424 for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); 425 iter != oneof_generators_.end(); ++iter) { 426 (*iter)->SetOneofIndexBase(sizeof_has_storage); 427 } 428 field_generators_.SetOneofIndexBase(sizeof_has_storage); 429 // sizeof_has_storage needs enough bits for the single fields that aren't in 430 // any oneof, and then one int32 for each oneof (to store the field number). 431 sizeof_has_storage += descriptor_->oneof_decl_count(); 432 433 printer->Print( 434 "\n" 435 "typedef struct $classname$__storage_ {\n" 436 " uint32_t _has_storage_[$sizeof_has_storage$];\n", 437 "classname", class_name_, 438 "sizeof_has_storage", SimpleItoa(sizeof_has_storage)); 439 printer->Indent(); 440 441 for (int i = 0; i < descriptor_->field_count(); i++) { 442 field_generators_.get(size_order_fields[i]) 443 .GenerateFieldStorageDeclaration(printer); 444 } 445 printer->Outdent(); 446 447 printer->Print("} $classname$__storage_;\n\n", "classname", class_name_); 448 449 450 printer->Print( 451 "// This method is threadsafe because it is initially called\n" 452 "// in +initialize for each subclass.\n" 453 "+ (GPBDescriptor *)descriptor {\n" 454 " static GPBDescriptor *descriptor = nil;\n" 455 " if (!descriptor) {\n"); 456 457 TextFormatDecodeData text_format_decode_data; 458 bool has_fields = descriptor_->field_count() > 0; 459 bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault(); 460 string field_description_type; 461 if (need_defaults) { 462 field_description_type = "GPBMessageFieldDescriptionWithDefault"; 463 } else { 464 field_description_type = "GPBMessageFieldDescription"; 465 } 466 if (has_fields) { 467 printer->Print( 468 " static $field_description_type$ fields[] = {\n", 469 "field_description_type", field_description_type); 470 printer->Indent(); 471 printer->Indent(); 472 printer->Indent(); 473 for (int i = 0; i < descriptor_->field_count(); ++i) { 474 const FieldGenerator& field_generator = 475 field_generators_.get(sorted_fields[i]); 476 field_generator.GenerateFieldDescription(printer, need_defaults); 477 if (field_generator.needs_textformat_name_support()) { 478 text_format_decode_data.AddString(sorted_fields[i]->number(), 479 field_generator.generated_objc_name(), 480 field_generator.raw_field_name()); 481 } 482 } 483 printer->Outdent(); 484 printer->Outdent(); 485 printer->Outdent(); 486 printer->Print( 487 " };\n"); 488 } 489 490 map<string, string> vars; 491 vars["classname"] = class_name_; 492 vars["rootclassname"] = root_classname_; 493 vars["fields"] = has_fields ? "fields" : "NULL"; 494 if (has_fields) { 495 vars["fields_count"] = 496 "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))"; 497 } else { 498 vars["fields_count"] = "0"; 499 } 500 501 std::vector<string> init_flags; 502 if (need_defaults) { 503 init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault"); 504 } 505 if (descriptor_->options().message_set_wire_format()) { 506 init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat"); 507 } 508 vars["init_flags"] = BuildFlagsString(init_flags); 509 510 printer->Print( 511 vars, 512 " GPBDescriptor *localDescriptor =\n" 513 " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" 514 " rootClass:[$rootclassname$ class]\n" 515 " file:$rootclassname$_FileDescriptor()\n" 516 " fields:$fields$\n" 517 " fieldCount:$fields_count$\n" 518 " storageSize:sizeof($classname$__storage_)\n" 519 " flags:$init_flags$];\n"); 520 if (oneof_generators_.size() != 0) { 521 printer->Print( 522 " static const char *oneofs[] = {\n"); 523 for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); 524 iter != oneof_generators_.end(); ++iter) { 525 printer->Print( 526 " \"$name$\",\n", 527 "name", (*iter)->DescriptorName()); 528 } 529 printer->Print( 530 " };\n" 531 " [localDescriptor setupOneofs:oneofs\n" 532 " count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n" 533 " firstHasIndex:$first_has_index$];\n", 534 "first_has_index", oneof_generators_[0]->HasIndexAsString()); 535 } 536 if (text_format_decode_data.num_entries() != 0) { 537 const string text_format_data_str(text_format_decode_data.Data()); 538 printer->Print( 539 "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" 540 " static const char *extraTextFormatInfo ="); 541 static const int kBytesPerLine = 40; // allow for escaping 542 for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) { 543 printer->Print( 544 "\n \"$data$\"", 545 "data", EscapeTrigraphs( 546 CEscape(text_format_data_str.substr(i, kBytesPerLine)))); 547 } 548 printer->Print( 549 ";\n" 550 " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n" 551 "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"); 552 } 553 if (sorted_extensions.size() != 0) { 554 printer->Print( 555 " static const GPBExtensionRange ranges[] = {\n"); 556 for (int i = 0; i < sorted_extensions.size(); i++) { 557 printer->Print(" { .start = $start$, .end = $end$ },\n", 558 "start", SimpleItoa(sorted_extensions[i]->start), 559 "end", SimpleItoa(sorted_extensions[i]->end)); 560 } 561 printer->Print( 562 " };\n" 563 " [localDescriptor setupExtensionRanges:ranges\n" 564 " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); 565 } 566 printer->Print( 567 " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" 568 " descriptor = localDescriptor;\n" 569 " }\n" 570 " return descriptor;\n" 571 "}\n\n" 572 "@end\n\n"); 573 574 for (int i = 0; i < descriptor_->field_count(); i++) { 575 field_generators_.get(descriptor_->field(i)) 576 .GenerateCFunctionImplementations(printer); 577 } 578 579 for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin(); 580 iter != oneof_generators_.end(); ++iter) { 581 (*iter)->GenerateClearFunctionImplementation(printer); 582 } 583 } 584 585 for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin(); 586 iter != enum_generators_.end(); ++iter) { 587 (*iter)->GenerateSource(printer); 588 } 589 590 for (vector<MessageGenerator*>::iterator iter = 591 nested_message_generators_.begin(); 592 iter != nested_message_generators_.end(); ++iter) { 593 (*iter)->GenerateSource(printer); 594 } 595 } 596 597 } // namespace objectivec 598 } // namespace compiler 599 } // namespace protobuf 600 } // namespace google 601