text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <algorithm>
#include <iostream>
#include <sstream>

#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/compiler/objectivec/objectivec_message.h>
#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
#include <google/protobuf/compiler/objectivec/objectivec_extension.h>
#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/wire_format_lite_inl.h>
#include <google/protobuf/descriptor.pb.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {

using internal::WireFormat;
using internal::WireFormatLite;

namespace {
struct FieldOrderingByNumber {
  inline bool operator()(const FieldDescriptor* a,
                         const FieldDescriptor* b) const {
    return a->number() < b->number();
  }
};

int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) {
  // The first item in the object structure is our uint32[] for has bits.
  // We then want to order things to make the instances as small as
  // possible. So we follow the has bits with:
  //   1. Anything always 4 bytes - float, *32, enums
  //   2. Anything that is always a pointer (they will be 8 bytes on 64 bit
  //      builds and 4 bytes on 32bit builds.
  //   3. Anything always 8 bytes - double, *64
  //
  // NOTE: Bools aren't listed, they were stored in the has bits.
  //
  // Why? Using 64bit builds as an example, this means worse case, we have
  // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes
  // are wasted before the 4 byte values. Then if we have an odd number of
  // those 4 byte values, the 8 byte values will be pushed down by 32bits to
  // keep them aligned. But the structure will end 8 byte aligned, so no
  // waste on the end. If you did the reverse order, you could waste 4 bytes
  // before the first 8 byte value (after the has array), then a single
  // bool on the end would need 7 bytes of padding to make the overall
  // structure 8 byte aligned; so 11 bytes, wasted total.

  // Anything repeated is a GPB*Array/NSArray, so pointer.
  if (descriptor->is_repeated()) {
    return 3;
  }

  switch (descriptor->type()) {
    // All always 8 bytes.
    case FieldDescriptor::TYPE_DOUBLE:
    case FieldDescriptor::TYPE_INT64:
    case FieldDescriptor::TYPE_SINT64:
    case FieldDescriptor::TYPE_UINT64:
    case FieldDescriptor::TYPE_SFIXED64:
    case FieldDescriptor::TYPE_FIXED64:
      return 4;

    // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes
    // depending on the build architecture.
    case FieldDescriptor::TYPE_GROUP:
    case FieldDescriptor::TYPE_MESSAGE:
    case FieldDescriptor::TYPE_STRING:
    case FieldDescriptor::TYPE_BYTES:
      return 3;

    // All always 4 bytes (enums are int32s).
    case FieldDescriptor::TYPE_FLOAT:
    case FieldDescriptor::TYPE_INT32:
    case FieldDescriptor::TYPE_SINT32:
    case FieldDescriptor::TYPE_UINT32:
    case FieldDescriptor::TYPE_SFIXED32:
    case FieldDescriptor::TYPE_FIXED32:
    case FieldDescriptor::TYPE_ENUM:
      return 2;

    // 0 bytes. Stored in the has bits.
    case FieldDescriptor::TYPE_BOOL:
      return 99;  // End of the list (doesn't really matter).
  }

  // Some compilers report reaching end of function even though all cases of
  // the enum are handed in the switch.
  GOOGLE_LOG(FATAL) << "Can't get here.";
  return 0;
}

struct FieldOrderingByStorageSize {
  inline bool operator()(const FieldDescriptor* a,
                         const FieldDescriptor* b) const {
    // Order by grouping.
    const int order_group_a = OrderGroupForFieldDescriptor(a);
    const int order_group_b = OrderGroupForFieldDescriptor(b);
    if (order_group_a != order_group_b) {
      return order_group_a < order_group_b;
    }
    // Within the group, order by field number (provides stable ordering).
    return a->number() < b->number();
  }
};

struct ExtensionRangeOrdering {
  bool operator()(const Descriptor::ExtensionRange* a,
                  const Descriptor::ExtensionRange* b) const {
    return a->start < b->start;
  }
};

// Sort the fields of the given Descriptor by number into a new[]'d array
// and return it.
const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
  const FieldDescriptor** fields =
      new const FieldDescriptor* [descriptor->field_count()];
  for (int i = 0; i < descriptor->field_count(); i++) {
    fields[i] = descriptor->field(i);
  }
  std::sort(fields, fields + descriptor->field_count(), FieldOrderingByNumber());
  return fields;
}

// Sort the fields of the given Descriptor by storage size into a new[]'d
// array and return it.
const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) {
  const FieldDescriptor** fields =
      new const FieldDescriptor* [descriptor->field_count()];
  for (int i = 0; i < descriptor->field_count(); i++) {
    fields[i] = descriptor->field(i);
  }
  std::sort(fields, fields + descriptor->field_count(),
       FieldOrderingByStorageSize());
  return fields;
}
}  // namespace

MessageGenerator::MessageGenerator(const string& root_classname,
                                   const Descriptor* descriptor,
                                   const Options& options)
    : root_classname_(root_classname),
      descriptor_(descriptor),
      field_generators_(descriptor, options),
      class_name_(ClassName(descriptor_)),
      deprecated_attribute_(
          GetOptionalDeprecatedAttribute(descriptor, descriptor->file(), false, true)) {

  for (int i = 0; i < descriptor_->extension_count(); i++) {
    extension_generators_.push_back(
        new ExtensionGenerator(class_name_, descriptor_->extension(i)));
  }

  for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
    OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i));
    oneof_generators_.push_back(generator);
  }

  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
    EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i));
    enum_generators_.push_back(generator);
  }

  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
    MessageGenerator* generator =
        new MessageGenerator(root_classname_,
                             descriptor_->nested_type(i),
                             options);
    nested_message_generators_.push_back(generator);
  }
}

MessageGenerator::~MessageGenerator() {
  STLDeleteContainerPointers(extension_generators_.begin(),
                             extension_generators_.end());
  STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
  STLDeleteContainerPointers(nested_message_generators_.begin(),
                             nested_message_generators_.end());
  STLDeleteContainerPointers(oneof_generators_.begin(),
                             oneof_generators_.end());
}

void MessageGenerator::GenerateStaticVariablesInitialization(
    io::Printer* printer) {
  for (vector<ExtensionGenerator*>::iterator iter =
           extension_generators_.begin();
       iter != extension_generators_.end(); ++iter) {
    (*iter)->GenerateStaticVariablesInitialization(printer);
  }

  for (vector<MessageGenerator*>::iterator iter =
           nested_message_generators_.begin();
       iter != nested_message_generators_.end(); ++iter) {
    (*iter)->GenerateStaticVariablesInitialization(printer);
  }
}

void MessageGenerator::DetermineForwardDeclarations(std::set<string>* fwd_decls) {
  if (!IsMapEntryMessage(descriptor_)) {
    for (int i = 0; i < descriptor_->field_count(); i++) {
      const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
      field_generators_.get(fieldDescriptor)
          .DetermineForwardDeclarations(fwd_decls);
    }
  }

  for (vector<MessageGenerator*>::iterator iter =
           nested_message_generators_.begin();
       iter != nested_message_generators_.end(); ++iter) {
    (*iter)->DetermineForwardDeclarations(fwd_decls);
  }
}

bool MessageGenerator::IncludesOneOfDefinition() const {
  if (!oneof_generators_.empty()) {
    return true;
  }

  for (vector<MessageGenerator*>::const_iterator iter =
           nested_message_generators_.begin();
       iter != nested_message_generators_.end(); ++iter) {
    if ((*iter)->IncludesOneOfDefinition()) {
      return true;
    }
  }

  return false;
}

void MessageGenerator::GenerateEnumHeader(io::Printer* printer) {
  for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
       iter != enum_generators_.end(); ++iter) {
    (*iter)->GenerateHeader(printer);
  }

  for (vector<MessageGenerator*>::iterator iter =
           nested_message_generators_.begin();
       iter != nested_message_generators_.end(); ++iter) {
    (*iter)->GenerateEnumHeader(printer);
  }
}

void MessageGenerator::GenerateExtensionRegistrationSource(
    io::Printer* printer) {
  for (vector<ExtensionGenerator*>::iterator iter =
           extension_generators_.begin();
       iter != extension_generators_.end(); ++iter) {
    (*iter)->GenerateRegistrationSource(printer);
  }

  for (vector<MessageGenerator*>::iterator iter =
           nested_message_generators_.begin();
       iter != nested_message_generators_.end(); ++iter) {
    (*iter)->GenerateExtensionRegistrationSource(printer);
  }
}

void MessageGenerator::GenerateMessageHeader(io::Printer* printer) {
  // This a a map entry message, just recurse and do nothing directly.
  if (IsMapEntryMessage(descriptor_)) {
    for (vector<MessageGenerator*>::iterator iter =
             nested_message_generators_.begin();
         iter != nested_message_generators_.end(); ++iter) {
      (*iter)->GenerateMessageHeader(printer);
    }
    return;
  }

  printer->Print(
      "#pragma mark - $classname$\n"
      "\n",
      "classname", class_name_);

  if (descriptor_->field_count()) {
    scoped_array<const FieldDescriptor*> sorted_fields(
        SortFieldsByNumber(descriptor_));

    printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n",
                   "classname", class_name_);
    printer->Indent();

    for (int i = 0; i < descriptor_->field_count(); i++) {
      field_generators_.get(sorted_fields[i])
          .GenerateFieldNumberConstant(printer);
    }

    printer->Outdent();
    printer->Print("};\n\n");
  }

  for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
       iter != oneof_generators_.end(); ++iter) {
    (*iter)->GenerateCaseEnum(printer);
  }

  string message_comments;
  SourceLocation location;
  if (descriptor_->GetSourceLocation(&location)) {
    message_comments = BuildCommentsString(location, false);
  } else {
    message_comments = "";
  }

  printer->Print(
      "$comments$$deprecated_attribute$@interface $classname$ : GPBMessage\n\n",
      "classname", class_name_,
      "deprecated_attribute", deprecated_attribute_,
      "comments", message_comments);

  vector<char> seen_oneofs(descriptor_->oneof_decl_count(), 0);
  for (int i = 0; i < descriptor_->field_count(); i++) {
    const FieldDescriptor* field = descriptor_->field(i);
    if (field->containing_oneof() != NULL) {
      const int oneof_index = field->containing_oneof()->index();
      if (!seen_oneofs[oneof_index]) {
        seen_oneofs[oneof_index] = 1;
        oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration(
            printer);
      }
    }
    field_generators_.get(field).GeneratePropertyDeclaration(printer);
  }

  printer->Print("@end\n\n");

  for (int i = 0; i < descriptor_->field_count(); i++) {
    field_generators_.get(descriptor_->field(i))
        .GenerateCFunctionDeclarations(printer);
  }

  if (!oneof_generators_.empty()) {
    for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
         iter != oneof_generators_.end(); ++iter) {
      (*iter)->GenerateClearFunctionDeclaration(printer);
    }
    printer->Print("\n");
  }

  if (descriptor_->extension_count() > 0) {
    printer->Print("@interface $classname$ (DynamicMethods)\n\n",
                   "classname", class_name_);
    for (vector<ExtensionGenerator*>::iterator iter =
             extension_generators_.begin();
         iter != extension_generators_.end(); ++iter) {
      (*iter)->GenerateMembersHeader(printer);
    }
    printer->Print("@end\n\n");
  }

  for (vector<MessageGenerator*>::iterator iter =
           nested_message_generators_.begin();
       iter != nested_message_generators_.end(); ++iter) {
    (*iter)->GenerateMessageHeader(printer);
  }
}

void MessageGenerator::GenerateSource(io::Printer* printer) {
  if (!IsMapEntryMessage(descriptor_)) {
    printer->Print(
        "#pragma mark - $classname$\n"
        "\n",
        "classname", class_name_);

    if (!deprecated_attribute_.empty()) {
      // No warnings when compiling the impl of this deprecated class.
      printer->Print(
          "#pragma clang diagnostic push\n"
          "#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n"
          "\n");
    }

    printer->Print("@implementation $classname$\n\n",
                   "classname", class_name_);

    for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
         iter != oneof_generators_.end(); ++iter) {
      (*iter)->GeneratePropertyImplementation(printer);
    }

    for (int i = 0; i < descriptor_->field_count(); i++) {
      field_generators_.get(descriptor_->field(i))
          .GeneratePropertyImplementation(printer);
    }

    scoped_array<const FieldDescriptor*> sorted_fields(
        SortFieldsByNumber(descriptor_));
    scoped_array<const FieldDescriptor*> size_order_fields(
        SortFieldsByStorageSize(descriptor_));

    vector<const Descriptor::ExtensionRange*> sorted_extensions;
    for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
      sorted_extensions.push_back(descriptor_->extension_range(i));
    }

    std::sort(sorted_extensions.begin(), sorted_extensions.end(),
         ExtensionRangeOrdering());

    // Assign has bits:
    // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing
    //    who needs has bits and assigning them.
    // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
    //    index that groups all the elements in the oneof.
    size_t num_has_bits = field_generators_.CalculateHasBits();
    size_t sizeof_has_storage = (num_has_bits + 31) / 32;
    if (sizeof_has_storage == 0) {
      // In the case where no field needs has bits, don't let the _has_storage_
      // end up as zero length (zero length arrays are sort of a grey area
      // since it has to be at the start of the struct). This also ensures a
      // field with only oneofs keeps the required negative indices they need.
      sizeof_has_storage = 1;
    }
    // Tell all the fields the oneof base.
    for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
         iter != oneof_generators_.end(); ++iter) {
      (*iter)->SetOneofIndexBase(sizeof_has_storage);
    }
    field_generators_.SetOneofIndexBase(sizeof_has_storage);
    // sizeof_has_storage needs enough bits for the single fields that aren't in
    // any oneof, and then one int32 for each oneof (to store the field number).
    sizeof_has_storage += descriptor_->oneof_decl_count();

    printer->Print(
        "\n"
        "typedef struct $classname$__storage_ {\n"
        "  uint32_t _has_storage_[$sizeof_has_storage$];\n",
        "classname", class_name_,
        "sizeof_has_storage", SimpleItoa(sizeof_has_storage));
    printer->Indent();

    for (int i = 0; i < descriptor_->field_count(); i++) {
      field_generators_.get(size_order_fields[i])
          .GenerateFieldStorageDeclaration(printer);
    }
    printer->Outdent();

    printer->Print("} $classname$__storage_;\n\n", "classname", class_name_);

    printer->Print(
        "// This method is threadsafe because it is initially called\n"
        "// in +initialize for each subclass.\n"
        "+ (GPBDescriptor *)descriptor {\n"
        "  static GPBDescriptor *descriptor = nil;\n"
        "  if (!descriptor) {\n");

    TextFormatDecodeData text_format_decode_data;
    bool has_fields = descriptor_->field_count() > 0;
    bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault();
    string field_description_type;
    if (need_defaults) {
      field_description_type = "GPBMessageFieldDescriptionWithDefault";
    } else {
      field_description_type = "GPBMessageFieldDescription";
    }
    if (has_fields) {
      printer->Print(
          "    static $field_description_type$ fields[] = {\n",
          "field_description_type", field_description_type);
      printer->Indent();
      printer->Indent();
      printer->Indent();
      for (int i = 0; i < descriptor_->field_count(); ++i) {
        const FieldGenerator& field_generator =
            field_generators_.get(sorted_fields[i]);
        field_generator.GenerateFieldDescription(printer, need_defaults);
        if (field_generator.needs_textformat_name_support()) {
          text_format_decode_data.AddString(sorted_fields[i]->number(),
                                            field_generator.generated_objc_name(),
                                            field_generator.raw_field_name());
        }
      }
      printer->Outdent();
      printer->Outdent();
      printer->Outdent();
      printer->Print(
          "    };\n");
    }

    std::map<string, string> vars;
    vars["classname"] = class_name_;
    vars["rootclassname"] = root_classname_;
    vars["fields"] = has_fields ? "fields" : "NULL";
    if (has_fields) {
      vars["fields_count"] =
          "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))";
    } else {
      vars["fields_count"] = "0";
    }

    std::vector<string> init_flags;
    if (need_defaults) {
      init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault");
    }
    if (descriptor_->options().message_set_wire_format()) {
      init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat");
    }
    vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION,
                                          init_flags);

    printer->Print(
        vars,
        "    GPBDescriptor *localDescriptor =\n"
        "        [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
        "                                     rootClass:[$rootclassname$ class]\n"
        "                                          file:$rootclassname$_FileDescriptor()\n"
        "                                        fields:$fields$\n"
        "                                    fieldCount:$fields_count$\n"
        "                                   storageSize:sizeof($classname$__storage_)\n"
        "                                         flags:$init_flags$];\n");
    if (oneof_generators_.size() != 0) {
      printer->Print(
          "    static const char *oneofs[] = {\n");
      for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
           iter != oneof_generators_.end(); ++iter) {
        printer->Print(
            "      \"$name$\",\n",
            "name", (*iter)->DescriptorName());
      }
      printer->Print(
          "    };\n"
          "    [localDescriptor setupOneofs:oneofs\n"
          "                           count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n"
          "                   firstHasIndex:$first_has_index$];\n",
          "first_has_index", oneof_generators_[0]->HasIndexAsString());
    }
    if (text_format_decode_data.num_entries() != 0) {
      const string text_format_data_str(text_format_decode_data.Data());
      printer->Print(
          "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
          "    static const char *extraTextFormatInfo =");
      static const int kBytesPerLine = 40;  // allow for escaping
      for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) {
        printer->Print(
            "\n        \"$data$\"",
            "data", EscapeTrigraphs(
                CEscape(text_format_data_str.substr(i, kBytesPerLine))));
      }
      printer->Print(
          ";\n"
          "    [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n"
          "#endif  // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n");
    }
    if (sorted_extensions.size() != 0) {
      printer->Print(
          "    static const GPBExtensionRange ranges[] = {\n");
      for (int i = 0; i < sorted_extensions.size(); i++) {
        printer->Print("      { .start = $start$, .end = $end$ },\n",
                       "start", SimpleItoa(sorted_extensions[i]->start),
                       "end", SimpleItoa(sorted_extensions[i]->end));
      }
      printer->Print(
          "    };\n"
          "    [localDescriptor setupExtensionRanges:ranges\n"
          "                                    count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
    }
    if (descriptor_->containing_type() != NULL) {
      string parent_class_name = ClassName(descriptor_->containing_type());
      printer->Print(
          "    [localDescriptor setupContainingMessageClassName:GPBStringifySymbol($parent_name$)];\n",
          "parent_name", parent_class_name);
    }
    string suffix_added;
    ClassName(descriptor_, &suffix_added);
    if (suffix_added.size() > 0) {
      printer->Print(
          "    [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n",
          "suffix", suffix_added);
    }
    printer->Print(
        "    NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
        "    descriptor = localDescriptor;\n"
        "  }\n"
        "  return descriptor;\n"
        "}\n\n"
        "@end\n\n");

    if (!deprecated_attribute_.empty()) {
      printer->Print(
          "#pragma clang diagnostic pop\n"
          "\n");
    }

    for (int i = 0; i < descriptor_->field_count(); i++) {
      field_generators_.get(descriptor_->field(i))
          .GenerateCFunctionImplementations(printer);
    }

    for (vector<OneofGenerator*>::iterator iter = oneof_generators_.begin();
         iter != oneof_generators_.end(); ++iter) {
      (*iter)->GenerateClearFunctionImplementation(printer);
    }
  }

  for (vector<EnumGenerator*>::iterator iter = enum_generators_.begin();
       iter != enum_generators_.end(); ++iter) {
    (*iter)->GenerateSource(printer);
  }

  for (vector<MessageGenerator*>::iterator iter =
           nested_message_generators_.begin();
       iter != nested_message_generators_.end(); ++iter) {
    (*iter)->GenerateSource(printer);
  }
}

}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Generates ObjectiveC code for a given .proto file.

#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__

#include <string>
#include <google/protobuf/compiler/code_generator.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {

// CodeGenerator implementation which generates a ObjectiveC source file and
// header.  If you create your own protocol compiler binary and you want it to
// support ObjectiveC output, you can do so by registering an instance of this
// CodeGenerator with the CommandLineInterface in your main() function.
class LIBPROTOC_EXPORT ObjectiveCGenerator : public CodeGenerator {
 public:
  ObjectiveCGenerator();
  ~ObjectiveCGenerator();

  // implements CodeGenerator ----------------------------------------
  bool HasGenerateAll() const;
  bool Generate(const FileDescriptor* file,
                const string& parameter,
                GeneratorContext* context,
                string* error) const;
  bool GenerateAll(const vector<const FileDescriptor*>& files,
                   const string& parameter,
                   GeneratorContext* context,
                   string* error) const;

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectiveCGenerator);
};

}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__

mime_type: text/plain


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2015 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <map>
#include <string>

#include <google/protobuf/compiler/objectivec/objectivec_map_field.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {

// MapFieldGenerator uses RepeatedFieldGenerator as the parent because it
// provides a bunch of things (no has* methods, comments for contained type,
// etc.).

namespace {

const char* MapEntryTypeName(const FieldDescriptor* descriptor, bool isKey) {
  ObjectiveCType type = GetObjectiveCType(descriptor);
  switch (type) {
    case OBJECTIVECTYPE_INT32:
      return "Int32";
    case OBJECTIVECTYPE_UINT32:
      return "UInt32";
    case OBJECTIVECTYPE_INT64:
      return "Int64";
    case OBJECTIVECTYPE_UINT64:
      return "UInt64";
    case OBJECTIVECTYPE_FLOAT:
      return "Float";
    case OBJECTIVECTYPE_DOUBLE:
      return "Double";
    case OBJECTIVECTYPE_BOOLEAN:
      return "Bool";
    case OBJECTIVECTYPE_STRING:
      return (isKey ? "String" : "Object");
    case OBJECTIVECTYPE_DATA:
      return "Object";
    case OBJECTIVECTYPE_ENUM:
      return "Enum";
    case OBJECTIVECTYPE_MESSAGE:
      return "Object";
  }

  // Some compilers report reaching end of function even though all cases of
  // the enum are handed in the switch.
  GOOGLE_LOG(FATAL) << "Can't get here.";
  return NULL;
}

}  // namespace

MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
                                     const Options& options)
    : RepeatedFieldGenerator(descriptor, options) {
  const FieldDescriptor* key_descriptor =
      descriptor->message_type()->FindFieldByName("key");
  const FieldDescriptor* value_descriptor =
      descriptor->message_type()->FindFieldByName("value");
  value_field_generator_.reset(FieldGenerator::Make(value_descriptor, options));

  // Pull over some variables_ from the value.
  variables_["field_type"] = value_field_generator_->variable("field_type");
  variables_["default"] = value_field_generator_->variable("default");
  variables_["default_name"] = value_field_generator_->variable("default_name");

  // Build custom field flags.
  std::vector<string> field_flags;
  field_flags.push_back("GPBFieldMapKey" + GetCapitalizedType(key_descriptor));
  // Pull over the current text format custom name values that was calculated.
  if (variables_["fieldflags"].find("GPBFieldTextFormatNameCustom") !=
      string::npos) {
    field_flags.push_back("GPBFieldTextFormatNameCustom");
  }
  // Pull over some info from the value's flags.
  const string& value_field_flags =
      value_field_generator_->variable("fieldflags");
  if (value_field_flags.find("GPBFieldHasDefaultValue") != string::npos) {
    field_flags.push_back("GPBFieldHasDefaultValue");
  }
  if (value_field_flags.find("GPBFieldHasEnumDescriptor") != string::npos) {
    field_flags.push_back("GPBFieldHasEnumDescriptor");
  }
  variables_["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);

  ObjectiveCType value_objc_type = GetObjectiveCType(value_descriptor);
  const bool value_is_object_type =
      ((value_objc_type == OBJECTIVECTYPE_STRING) ||
       (value_objc_type == OBJECTIVECTYPE_DATA) ||
       (value_objc_type == OBJECTIVECTYPE_MESSAGE));
  if ((GetObjectiveCType(key_descriptor) == OBJECTIVECTYPE_STRING) &&
      value_is_object_type) {
    variables_["array_storage_type"] = "NSMutableDictionary";
    variables_["array_property_type"] =
        "NSMutableDictionary<NSString*, " +
        value_field_generator_->variable("storage_type") + "*>";
  } else {
    string class_name("GPB");
    class_name += MapEntryTypeName(key_descriptor, true);
    class_name += MapEntryTypeName(value_descriptor, false);
    class_name += "Dictionary";
    variables_["array_storage_type"] = class_name;
    if (value_is_object_type) {
      variables_["array_property_type"] =
          class_name + "<" +
          value_field_generator_->variable("storage_type") + "*>";
    }
  }

  variables_["dataTypeSpecific_name"] =
      value_field_generator_->variable("dataTypeSpecific_name");
  variables_["dataTypeSpecific_value"] =
      value_field_generator_->variable("dataTypeSpecific_value");
}

MapFieldGenerator::~MapFieldGenerator() {}

void MapFieldGenerator::FinishInitialization(void) {
  RepeatedFieldGenerator::FinishInitialization();
  // Use the array_comment support in RepeatedFieldGenerator to output what the
  // values in the map are.
  const FieldDescriptor* value_descriptor =
      descriptor_->message_type()->FindFieldByName("value");
  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_ENUM) {
    variables_["array_comment"] =
        "// |" + variables_["name"] + "| values are |" + value_field_generator_->variable("storage_type") + "|\n";
  }
}

void MapFieldGenerator::DetermineForwardDeclarations(
    std::set<string>* fwd_decls) const {
  RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls);
  const FieldDescriptor* value_descriptor =
      descriptor_->message_type()->FindFieldByName("value");
  if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) {
    const string& value_storage_type =
        value_field_generator_->variable("storage_type");
    fwd_decls->insert("@class " + value_storage_type);
  }
}

}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/compiler/objectivec/objectivec_file.h>
#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
#include <google/protobuf/compiler/objectivec/objectivec_extension.h>
#include <google/protobuf/compiler/objectivec/objectivec_message.h>
#include <google/protobuf/compiler/code_generator.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/stubs/stl_util.h>
#include <google/protobuf/stubs/strutil.h>
#include <algorithm> // std::find()
#include <iostream>
#include <sstream>

// NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
// error cases, so it seems to be ok to use as a back door for errors.

namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {

namespace {

// This is also found in GPBBootstrap.h, and needs to be kept in sync.
const int32 GOOGLE_PROTOBUF_OBJC_VERSION = 30002;

const char* kHeaderExtension = ".pbobjc.h";

// Checks if a message contains any extension definitions (on the message or
// a nested message under it).
bool MessageContainsExtensions(const Descriptor* message) {
  if (message->extension_count() > 0) {
    return true;
  }
  for (int i = 0; i < message->nested_type_count(); i++) {
    if (MessageContainsExtensions(message->nested_type(i))) {
      return true;
    }
  }
  return false;
}

// Checks if the file contains any extensions definitions (at the root or
// nested under a message).
bool FileContainsExtensions(const FileDescriptor* file) {
  if (file->extension_count() > 0) {
    return true;
  }
  for (int i = 0; i < file->message_type_count(); i++) {
    if (MessageContainsExtensions(file->message_type(i))) {
      return true;
    }
  }
  return false;
}

// Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all
// deps as visited and prunes them from the needed files list.
void PruneFileAndDepsMarkingAsVisited(
    const FileDescriptor* file,
    vector<const FileDescriptor*>* files,
    std::set<const FileDescriptor*>* files_visited) {
  vector<const FileDescriptor*>::iterator iter =
      std::find(files->begin(), files->end(), file);
  if (iter != files->end()) {
    files->erase(iter);
  }
  files_visited->insert(file);
  for (int i = 0; i < file->dependency_count(); i++) {
    PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited);
  }
}

// Helper for CollectMinimalFileDepsContainingExtensions.
void CollectMinimalFileDepsContainingExtensionsWorker(
    const FileDescriptor* file,
    vector<const FileDescriptor*>* files,
    std::set<const FileDescriptor*>* files_visited) {
  if (files_visited->find(file) != files_visited->end()) {
    return;
  }
  files_visited->insert(file);

  if (FileContainsExtensions(file)) {
    files->push_back(file);
    for (int i = 0; i < file->dependency_count(); i++) {
      const FileDescriptor* dep = file->dependency(i);
      PruneFileAndDepsMarkingAsVisited(dep, files, files_visited);
    }
  } else {
    for (int i = 0; i < file->dependency_count(); i++) {
      const FileDescriptor* dep = file->dependency(i);
      CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
                                                       files_visited);
    }
  }
}

// Collect the deps of the given file that contain extensions. This can be used to
// create the chain of roots that need to be wired together.
//
// NOTE: If any changes are made to this and the supporting functions, you will
// need to manually validate what the generated code is for the test files:
//   objectivec/Tests/unittest_extension_chain_*.proto
// There are comments about what the expected code should be line and limited
// testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports
// specifically).
void CollectMinimalFileDepsContainingExtensions(
    const FileDescriptor* file,
    vector<const FileDescriptor*>* files) {
  std::set<const FileDescriptor*> files_visited;
  for (int i = 0; i < file->dependency_count(); i++) {
    const FileDescriptor* dep = file->dependency(i);
    CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
                                                     &files_visited);
  }
}

bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) {
  for (int i = 0; i < file->dependency_count(); i++) {
    if (dep == file->dependency(i)) {
      return true;
    }
  }
  return false;
}

}  // namespace

FileGenerator::FileGenerator(const FileDescriptor *file, const Options& options)
    : file_(file),
      root_class_name_(FileClassName(file)),
      options_(options) {
  for (int i = 0; i < file_->enum_type_count(); i++) {
    EnumGenerator *generator = new EnumGenerator(file_->enum_type(i));
    enum_generators_.push_back(generator);
  }
  for (int i = 0; i < file_->message_type_count(); i++) {
    MessageGenerator *generator =
        new MessageGenerator(root_class_name_, file_->message_type(i), options_);
    message_generators_.push_back(generator);
  }
  for (int i = 0; i < file_->extension_count(); i++) {
    ExtensionGenerator *generator =
        new ExtensionGenerator(root_class_name_, file_->extension(i));
    extension_generators_.push_back(generator);
  }
}

FileGenerator::~FileGenerator() {
  STLDeleteContainerPointers(enum_generators_.begin(), enum_generators_.end());
  STLDeleteContainerPointers(message_generators_.begin(),
                             message_generators_.end());
  STLDeleteContainerPointers(extension_generators_.begin(),
                             extension_generators_.end());
}

void FileGenerator::GenerateHeader(io::Printer *printer) {
  PrintFileRuntimePreamble(printer, "GPBProtocolBuffers.h");

  // Add some verification that the generated code matches the source the
  // code is being compiled with.
  // NOTE: This captures the raw numeric values at the time the generator was
  // compiled, since that will be the versions for the ObjC runtime at that
  // time.  The constants in the generated code will then get their values at
  // at compile time (so checking against the headers being used to compile).
  printer->Print(
      "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n"
      "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n"
      "#endif\n"
      "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n"
      "#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n"
      "#endif\n"
      "\n",
      "google_protobuf_objc_version", SimpleItoa(GOOGLE_PROTOBUF_OBJC_VERSION));

  // #import any headers for "public imports" in the proto file.
  {
    ImportWriter import_writer(
        options_.generate_for_named_framework,
        options_.named_framework_to_proto_path_mappings_path);
    const string header_extension(kHeaderExtension);
    for (int i = 0; i < file_->public_dependency_count(); i++) {
      import_writer.AddFile(file_->public_dependency(i), header_extension);
    }
    import_writer.Print(printer);
  }

  // Note:
  //  deprecated-declarations suppression is only needed if some place in this
  //    proto file is something deprecated or if it references something from
  //    another file that is deprecated.
  printer->Print(
      "// @@protoc_insertion_point(imports)\n"
      "\n"
      "#pragma clang diagnostic push\n"
      "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
      "\n"
      "CF_EXTERN_C_BEGIN\n"
      "\n");

  std::set<string> fwd_decls;
  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
       iter != message_generators_.end(); ++iter) {
    (*iter)->DetermineForwardDeclarations(&fwd_decls);
  }
  for (std::set<string>::const_iterator i(fwd_decls.begin());
       i != fwd_decls.end(); ++i) {
    printer->Print("$value$;\n", "value", *i);
  }
  if (fwd_decls.begin() != fwd_decls.end()) {
    printer->Print("\n");
  }

  printer->Print(
      "NS_ASSUME_NONNULL_BEGIN\n"
      "\n");

  // need to write out all enums first
  for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
       iter != enum_generators_.end(); ++iter) {
    (*iter)->GenerateHeader(printer);
  }

  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
       iter != message_generators_.end(); ++iter) {
    (*iter)->GenerateEnumHeader(printer);
  }

  // For extensions to chain together, the Root gets created even if there
  // are no extensions.
  printer->Print(
      "#pragma mark - $root_class_name$\n"
      "\n"
      "/**\n"
      " * Exposes the extension registry for this file.\n"
      " *\n"
      " * The base class provides:\n"
      " * @code\n"
      " *   + (GPBExtensionRegistry *)extensionRegistry;\n"
      " * @endcode\n"
      " * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n"
      " * this file and all files that it depends on.\n"
      " **/\n"
      "@interface $root_class_name$ : GPBRootObject\n"
      "@end\n"
      "\n",
      "root_class_name", root_class_name_);

  if (extension_generators_.size() > 0) {
    // The dynamic methods block is only needed if there are extensions.
    printer->Print(
        "@interface $root_class_name$ (DynamicMethods)\n",
        "root_class_name", root_class_name_);

    for (vector<ExtensionGenerator *>::iterator iter =
             extension_generators_.begin();
         iter != extension_generators_.end(); ++iter) {
      (*iter)->GenerateMembersHeader(printer);
    }

    printer->Print("@end\n\n");
  }  // extension_generators_.size() > 0

  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
       iter != message_generators_.end(); ++iter) {
    (*iter)->GenerateMessageHeader(printer);
  }

  printer->Print(
      "NS_ASSUME_NONNULL_END\n"
      "\n"
      "CF_EXTERN_C_END\n"
      "\n"
      "#pragma clang diagnostic pop\n"
      "\n"
      "// @@protoc_insertion_point(global_scope)\n");
}

void FileGenerator::GenerateSource(io::Printer *printer) {
  // #import the runtime support.
  PrintFileRuntimePreamble(printer, "GPBProtocolBuffers_RuntimeSupport.h");

  vector<const FileDescriptor*> deps_with_extensions;
  CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions);

  {
    ImportWriter import_writer(
        options_.generate_for_named_framework,
        options_.named_framework_to_proto_path_mappings_path);
    const string header_extension(kHeaderExtension);

    // #import the header for this proto file.
    import_writer.AddFile(file_, header_extension);

    // #import the headers for anything that a plain dependency of this proto
    // file (that means they were just an include, not a "public" include).
    std::set<string> public_import_names;
    for (int i = 0; i < file_->public_dependency_count(); i++) {
      public_import_names.insert(file_->public_dependency(i)->name());
    }
    for (int i = 0; i < file_->dependency_count(); i++) {
      const FileDescriptor *dep = file_->dependency(i);
      bool public_import = (public_import_names.count(dep->name()) != 0);
      if (!public_import) {
        import_writer.AddFile(dep, header_extension);
      }
    }

    // If any indirect dependency provided extensions, it needs to be directly
    // imported so it can get merged into the root's extensions registry.
    // See the Note by CollectMinimalFileDepsContainingExtensions before
    // changing this.
    for (vector<const FileDescriptor *>::iterator iter =
             deps_with_extensions.begin();
         iter != deps_with_extensions.end(); ++iter) {
      if (!IsDirectDependency(*iter, file_)) {
        import_writer.AddFile(*iter, header_extension);
      }
    }

    import_writer.Print(printer);
  }

  bool includes_oneof = false;
  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
       iter != message_generators_.end(); ++iter) {
    if ((*iter)->IncludesOneOfDefinition()) {
      includes_oneof = true;
      break;
    }
  }

  // Note:
  //  deprecated-declarations suppression is only needed if some place in this
  //    proto file is something deprecated or if it references something from
  //    another file that is deprecated.
  printer->Print(
      "// @@protoc_insertion_point(imports)\n"
      "\n"
      "#pragma clang diagnostic push\n"
      "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n");
  if (includes_oneof) {
    // The generated code for oneof's uses direct ivar access, suppress the
    // warning incase developer turn that on in the context they compile the
    // generated code.
    printer->Print(
        "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n");
  }

  printer->Print(
      "\n"
      "#pragma mark - $root_class_name$\n"
      "\n"
      "@implementation $root_class_name$\n\n",
      "root_class_name", root_class_name_);

  const bool file_contains_extensions = FileContainsExtensions(file_);

  // If there were any extensions or this file has any dependencies, output
  // a registry to override to create the file specific registry.
  if (file_contains_extensions || !deps_with_extensions.empty()) {
    printer->Print(
        "+ (GPBExtensionRegistry*)extensionRegistry {\n"
        "  // This is called by +initialize so there is no need to worry\n"
        "  // about thread safety and initialization of registry.\n"
        "  static GPBExtensionRegistry* registry = nil;\n"
        "  if (!registry) {\n"
        "    GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"
        "    registry = [[GPBExtensionRegistry alloc] init];\n");

    printer->Indent();
    printer->Indent();

    if (file_contains_extensions) {
      printer->Print(
          "static GPBExtensionDescription descriptions[] = {\n");
      printer->Indent();
      for (vector<ExtensionGenerator *>::iterator iter =
               extension_generators_.begin();
           iter != extension_generators_.end(); ++iter) {
        (*iter)->GenerateStaticVariablesInitialization(printer);
      }
      for (vector<MessageGenerator *>::iterator iter =
               message_generators_.begin();
           iter != message_generators_.end(); ++iter) {
        (*iter)->GenerateStaticVariablesInitialization(printer);
      }
      printer->Outdent();
      printer->Print(
          "};\n"
          "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n"
          "  GPBExtensionDescriptor *extension =\n"
          "      [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]];\n"
          "  [registry addExtension:extension];\n"
          "  [self globallyRegisterExtension:extension];\n"
          "  [extension release];\n"
          "}\n");
    }

    if (deps_with_extensions.empty()) {
      printer->Print(
          "// None of the imports (direct or indirect) defined extensions, so no need to add\n"
          "// them to this registry.\n");
    } else {
      printer->Print(
          "// Merge in the imports (direct or indirect) that defined extensions.\n");
      for (vector<const FileDescriptor *>::iterator iter =
               deps_with_extensions.begin();
           iter != deps_with_extensions.end(); ++iter) {
        const string root_class_name(FileClassName((*iter)));
        printer->Print(
            "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
            "dependency", root_class_name);
      }
    }

    printer->Outdent();
    printer->Outdent();

    printer->Print(
        "  }\n"
        "  return registry;\n"
        "}\n");
  } else {
    if (file_->dependency_count() > 0) {
      printer->Print(
          "// No extensions in the file and none of the imports (direct or indirect)\n"
          "// defined extensions, so no need to generate +extensionRegistry.\n");
    } else {
      printer->Print(
          "// No extensions in the file and no imports, so no need to generate\n"
          "// +extensionRegistry.\n");
    }
  }

  printer->Print("\n@end\n\n");

  // File descriptor only needed if there are messages to use it.
  if (message_generators_.size() > 0) {
    std::map<string, string> vars;
    vars["root_class_name"] = root_class_name_;
    vars["package"] = file_->package();
    vars["objc_prefix"] = FileClassPrefix(file_);
    switch (file_->syntax()) {
      case FileDescriptor::SYNTAX_UNKNOWN:
        vars["syntax"] = "GPBFileSyntaxUnknown";
        break;
      case FileDescriptor::SYNTAX_PROTO2:
        vars["syntax"] = "GPBFileSyntaxProto2";
        break;
      case FileDescriptor::SYNTAX_PROTO3:
        vars["syntax"] = "GPBFileSyntaxProto3";
        break;
    }
    printer->Print(vars,
        "#pragma mark - $root_class_name$_FileDescriptor\n"
        "\n"
        "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
        "  // This is called by +initialize so there is no need to worry\n"
        "  // about thread safety of the singleton.\n"
        "  static GPBFileDescriptor *descriptor = NULL;\n"
        "  if (!descriptor) {\n"
        "    GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n");
    if (vars["objc_prefix"].size() > 0) {
      printer->Print(
          vars,
          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
          "                                                 objcPrefix:@\"$objc_prefix$\"\n"
          "                                                     syntax:$syntax$];\n");
    } else {
      printer->Print(
          vars,
          "    descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
          "                                                     syntax:$syntax$];\n");
    }
    printer->Print(
        "  }\n"
        "  return descriptor;\n"
        "}\n"
        "\n");
  }

  for (vector<EnumGenerator *>::iterator iter = enum_generators_.begin();
       iter != enum_generators_.end(); ++iter) {
    (*iter)->GenerateSource(printer);
  }
  for (vector<MessageGenerator *>::iterator iter = message_generators_.begin();
       iter != message_generators_.end(); ++iter) {
    (*iter)->GenerateSource(printer);
  }

  printer->Print(
    "\n"
    "#pragma clang diagnostic pop\n"
    "\n"
    "// @@protoc_insertion_point(global_scope)\n");
}

// Helper to print the import of the runtime support at the top of generated
// files. This currently only supports the runtime coming from a framework
// as defined by the official CocoaPod.
void FileGenerator::PrintFileRuntimePreamble(
    io::Printer* printer, const string& header_to_import) const {
  printer->Print(
      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
      "// source: $filename$\n"
      "\n",
      "filename", file_->name());

  const string framework_name(ProtobufLibraryFrameworkName);
  const string cpp_symbol(ProtobufFrameworkImportSymbol(framework_name));
  printer->Print(
      "// This CPP symbol can be defined to use imports that match up to the framework\n"
      "// imports needed when using CocoaPods.\n"
      "#if !defined($cpp_symbol$)\n"
      " #define $cpp_symbol$ 0\n"
      "#endif\n"
      "\n"
      "#if $cpp_symbol$\n"
      " #import <$framework_name$/$header$>\n"
      "#else\n"
      " #import \"$header$\"\n"
      "#endif\n"
      "\n",
      "cpp_symbol", cpp_symbol,
      "header", header_to_import,
      "framework_name", framework_name);
}

}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__

#include <map>
#include <string>
#include <google/protobuf/compiler/objectivec/objectivec_field.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {

class EnumFieldGenerator : public SingleFieldGenerator {
  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
                                              const Options& options);

 public:
  virtual void GenerateCFunctionDeclarations(io::Printer* printer) const;
  virtual void GenerateCFunctionImplementations(io::Printer* printer) const;
  virtual void DetermineForwardDeclarations(std::set<string>* fwd_decls) const;

 protected:
  EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
  virtual ~EnumFieldGenerator();

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
};

class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator {
  friend FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
                                              const Options& options);

 public:
  virtual void FinishInitialization();

 protected:
  RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor,
                             const Options& options);
  virtual ~RepeatedEnumFieldGenerator();

 private:
  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
};

}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_FIELD_H__


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_EXTENSION_H__

#include <google/protobuf/stubs/common.h>

namespace google {
namespace protobuf {
class FieldDescriptor;  // descriptor.h
namespace io {
class Printer;  // printer.h
}
}

namespace protobuf {
namespace compiler {
namespace objectivec {

class ExtensionGenerator {
 public:
  ExtensionGenerator(const string& root_class_name,
                     const FieldDescriptor* descriptor);
  ~ExtensionGenerator();

  void GenerateMembersHeader(io::Printer* printer);
  void GenerateStaticVariablesInitialization(io::Printer* printer);
  void GenerateRegistrationSource(io::Printer* printer);

 private:
  string method_name_;
  string root_class_and_method_name_;
  const FieldDescriptor* descriptor_;

  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
};
}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_MESSAGE_H__


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <map>
#include <string>

#include <google/protobuf/compiler/objectivec/objectivec_enum.h>
#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/stubs/strutil.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {

EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor)
    : descriptor_(descriptor),
      name_(EnumName(descriptor_)) {
  for (int i = 0; i < descriptor_->value_count(); i++) {
    const EnumValueDescriptor* value = descriptor_->value(i);
    const EnumValueDescriptor* canonical_value =
        descriptor_->FindValueByNumber(value->number());

    if (value == canonical_value) {
      base_values_.push_back(value);
    }
    all_values_.push_back(value);
  }
}

EnumGenerator::~EnumGenerator() {}

void EnumGenerator::GenerateHeader(io::Printer* printer) {
  string enum_comments;
  SourceLocation location;
  if (descriptor_->GetSourceLocation(&location)) {
    enum_comments = BuildCommentsString(location, true);
  } else {
    enum_comments = "";
  }

  printer->Print(
      "#pragma mark - Enum $name$\n"
      "\n",
      "name", name_);

  printer->Print("$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n",
                 "comments", enum_comments,
                 "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, descriptor_->file()),
                 "name", name_);
  printer->Indent();

  if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
    // Include the unknown value.
    printer->Print(
      "/**\n"
      " * Value used if any message's field encounters a value that is not defined\n"
      " * by this enum. The message will also have C functions to get/set the rawValue\n"
      " * of the field.\n"
      " **/\n"
      "$name$_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,\n",
      "name", name_);
  }
  for (int i = 0; i < all_values_.size(); i++) {
    SourceLocation location;
    if (all_values_[i]->GetSourceLocation(&location)) {
      string comments = BuildCommentsString(location, true).c_str();
      if (comments.length() > 0) {
        if (i > 0) {
          printer->Print("\n");
        }
        printer->Print(comments.c_str());
      }
    }

    printer->Print(
        "$name$$deprecated_attribute$ = $value$,\n",
        "name", EnumValueName(all_values_[i]),
        "deprecated_attribute", GetOptionalDeprecatedAttribute(all_values_[i]),
        "value", SimpleItoa(all_values_[i]->number()));
  }
  printer->Outdent();
  printer->Print(
      "};\n"
      "\n"
      "GPBEnumDescriptor *$name$_EnumDescriptor(void);\n"
      "\n"
      "/**\n"
      " * Checks to see if the given value is defined by the enum or was not known at\n"
      " * the time this source was generated.\n"
      " **/\n"
      "BOOL $name$_IsValidValue(int32_t value);\n"
      "\n",
      "name", name_);
}

void EnumGenerator::GenerateSource(io::Printer* printer) {
  printer->Print(
      "#pragma mark - Enum $name$\n"
      "\n",
      "name", name_);

  // Note: For the TextFormat decode info, we can't use the enum value as
  // the key because protocol buffer enums have 'allow_alias', which lets
  // a value be used more than once. Instead, the index into the list of
  // enum value descriptions is used. Note: start with -1 so the first one
  // will be zero.
  TextFormatDecodeData text_format_decode_data;
  int enum_value_description_key = -1;
  string text_blob;

  for (int i = 0; i < all_values_.size(); i++) {
    ++enum_value_description_key;
    string short_name(EnumValueShortName(all_values_[i]));
    text_blob += short_name + '\0';
    if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) {
      text_format_decode_data.AddString(enum_value_description_key, short_name,
                                        all_values_[i]->name());
    }
  }

  printer->Print(
      "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n"
      "  static GPBEnumDescriptor *descriptor = NULL;\n"
      "  if (!descriptor) {\n",
      "name", name_);

  static const int kBytesPerLine = 40;  // allow for escaping
  printer->Print(
      "    static const char *valueNames =");
  for (int i = 0; i < text_blob.size(); i += kBytesPerLine) {
    printer->Print(
        "\n        \"$data$\"",
        "data", EscapeTrigraphs(CEscape(text_blob.substr(i, kBytesPerLine))));
  }
  printer->Print(
      ";\n"
      "    static const int32_t values[] = {\n");
  for (int i = 0; i < all_values_.size(); i++) {
    printer->Print("        $name$,\n",  "name", EnumValueName(all_values_[i]));
  }
  printer->Print("    };\n");

  if (text_format_decode_data.num_entries() == 0) {
    printer->Print(
        "    GPBEnumDescriptor *worker =\n"
        "        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
        "                                       valueNames:valueNames\n"
        "                                           values:values\n"
        "                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n"
        "                                     enumVerifier:$name$_IsValidValue];\n",
        "name", name_);
    } else {
      printer->Print(
        "    static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n"
        "    GPBEnumDescriptor *worker =\n"
        "        [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n"
        "                                       valueNames:valueNames\n"
        "                                           values:values\n"
        "                                            count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n"
        "                                     enumVerifier:$name$_IsValidValue\n"
        "                              extraTextFormatInfo:extraTextFormatInfo];\n",
        "name", name_,
        "extraTextFormatInfo", CEscape(text_format_decode_data.Data()));
    }
    printer->Print(
      "    if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {\n"
      "      [worker release];\n"
      "    }\n"
      "  }\n"
      "  return descriptor;\n"
      "}\n\n");

  printer->Print(
      "BOOL $name$_IsValidValue(int32_t value__) {\n"
      "  switch (value__) {\n",
      "name", name_);

  for (int i = 0; i < base_values_.size(); i++) {
    printer->Print(
        "    case $name$:\n",
        "name", EnumValueName(base_values_[i]));
  }

  printer->Print(
      "      return YES;\n"
      "    default:\n"
      "      return NO;\n"
      "  }\n"
      "}\n\n");
}
}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__

#include <string>
#include <set>
#include <vector>
#include <google/protobuf/descriptor.h>

namespace google {
namespace protobuf {
namespace io {
class Printer;  // printer.h
}
}

namespace protobuf {
namespace compiler {
namespace objectivec {

class EnumGenerator {
 public:
  explicit EnumGenerator(const EnumDescriptor* descriptor);
  ~EnumGenerator();

  void GenerateHeader(io::Printer* printer);
  void GenerateSource(io::Printer* printer);

  const string& name() const { return name_; }

 private:
  const EnumDescriptor* descriptor_;
  vector<const EnumValueDescriptor*> base_values_;
  vector<const EnumValueDescriptor*> all_values_;
  const string name_;

  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
};

}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google
#endif  // GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_ENUM_H__


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <iostream>
#include <google/protobuf/compiler/objectivec/objectivec_generator.h>
#include <google/protobuf/compiler/objectivec/objectivec_file.h>
#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/zero_copy_stream.h>
#include <google/protobuf/stubs/strutil.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {

ObjectiveCGenerator::ObjectiveCGenerator() {}

ObjectiveCGenerator::~ObjectiveCGenerator() {}

bool ObjectiveCGenerator::HasGenerateAll() const {
  return true;
}

bool ObjectiveCGenerator::Generate(const FileDescriptor* file,
                                   const string& parameter,
                                   GeneratorContext* context,
                                   string* error) const {
  *error = "Unimplemented Generate() method. Call GenerateAll() instead.";
  return false;
}

bool ObjectiveCGenerator::GenerateAll(const vector<const FileDescriptor*>& files,
                                      const string& parameter,
                                      GeneratorContext* context,
                                      string* error) const {
  // -----------------------------------------------------------------
  // Parse generator options. These options are passed to the compiler using the
  // --objc_opt flag. The options are passed as a comma separated list of
  // options along with their values. If the option appears multiple times, only
  // the last value will be considered.
  //
  // e.g. protoc ... --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework

  Options generation_options;

  vector<pair<string, string> > options;
  ParseGeneratorParameter(parameter, &options);
  for (int i = 0; i < options.size(); i++) {
    if (options[i].first == "expected_prefixes_path") {
      // Path to find a file containing the expected prefixes
      // (objc_class_prefix "PREFIX") for proto packages (package NAME). The
      // generator will then issue warnings/errors if in the proto files being
      // generated the option is not listed/wrong/etc in the file.
      //
      // The format of the file is:
      //   - An entry is a line of "package=prefix".
      //   - Comments start with "#".
      //   - A comment can go on a line after a expected package/prefix pair.
      //     (i.e. - "package=prefix # comment")
      //
      // There is no validation that the prefixes are good prefixes, it is
      // assumed that they are when you create the file.
      generation_options.expected_prefixes_path = options[i].second;
    } else if (options[i].first == "generate_for_named_framework") {
      // The name of the framework that protos are being generated for. This
      // will cause the #import statements to be framework based using this
      // name (i.e. - "#import <NAME/proto.pbobjc.h>).
      //
      // NOTE: If this option is used with
      // named_framework_to_proto_path_mappings_path, then this is effectively
      // the "default" framework name used for everything that wasn't mapped by
      // the mapping file.
      generation_options.generate_for_named_framework = options[i].second;
    } else if (options[i].first == "named_framework_to_proto_path_mappings_path") {
      // Path to find a file containing the list of framework names and proto
      // files. The generator uses this to decide if a proto file
      // referenced should use a framework style import vs. a user level import
      // (#import <FRAMEWORK/file.pbobjc.h> vs #import "dir/file.pbobjc.h").
      //
      // The format of the file is:
      //   - An entry is a line of "frameworkName: file.proto, dir/file2.proto".
      //   - Comments start with "#".
      //   - A comment can go on a line after a expected package/prefix pair.
      //     (i.e. - "frameworkName: file.proto # comment")
      //
      // Any number of files can be listed for a framework, just separate them
      // with commas.
      //
      // There can be multiple lines listing the same frameworkName incase it
      // has a lot of proto files included in it; having multiple lines makes
      // things easier to read. If a proto file is not configured in the
      // mappings file, it will use the default framework name if one was passed
      // with generate_for_named_framework, or the relative path to it's include
      // path otherwise.
      generation_options.named_framework_to_proto_path_mappings_path = options[i].second;
    } else {
      *error = "error: Unknown generator option: " + options[i].first;
      return false;
    }
  }

  // -----------------------------------------------------------------

  // Validate the objc prefix/package pairings.
  if (!ValidateObjCClassPrefixes(files, generation_options, error)) {
    // *error will have been filled in.
    return false;
  }

  for (int i = 0; i < files.size(); i++) {
    const FileDescriptor* file = files[i];
    FileGenerator file_generator(file, generation_options);
    string filepath = FilePath(file);

    // Generate header.
    {
      scoped_ptr<io::ZeroCopyOutputStream> output(
          context->Open(filepath + ".pbobjc.h"));
      io::Printer printer(output.get(), '$');
      file_generator.GenerateHeader(&printer);
    }

    // Generate m file.
    {
      scoped_ptr<io::ZeroCopyOutputStream> output(
          context->Open(filepath + ".pbobjc.m"));
      io::Printer printer(output.get(), '$');
      file_generator.GenerateSource(&printer);
    }
  }

  return true;
}

}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google


text:
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <iostream>

#include <google/protobuf/compiler/objectivec/objectivec_field.h>
#include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
#include <google/protobuf/compiler/objectivec/objectivec_enum_field.h>
#include <google/protobuf/compiler/objectivec/objectivec_map_field.h>
#include <google/protobuf/compiler/objectivec/objectivec_message_field.h>
#include <google/protobuf/compiler/objectivec/objectivec_primitive_field.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/strutil.h>

namespace google {
namespace protobuf {
namespace compiler {
namespace objectivec {

namespace {

void SetCommonFieldVariables(const FieldDescriptor* descriptor,
                             std::map<string, string>* variables) {
  string camel_case_name = FieldName(descriptor);
  string raw_field_name;
  if (descriptor->type() == FieldDescriptor::TYPE_GROUP) {
    raw_field_name = descriptor->message_type()->name();
  } else {
    raw_field_name = descriptor->name();
  }
  // The logic here has to match -[GGPBFieldDescriptor textFormatName].
  const string un_camel_case_name(
      UnCamelCaseFieldName(camel_case_name, descriptor));
  const bool needs_custom_name = (raw_field_name != un_camel_case_name);

  SourceLocation location;
  if (descriptor->GetSourceLocation(&location)) {
    (*variables)["comments"] = BuildCommentsString(location, true);
  } else {
    (*variables)["comments"] = "\n";
  }
  const string& classname = ClassName(descriptor->containing_type());
  (*variables)["classname"] = classname;
  (*variables)["name"] = camel_case_name;
  const string& capitalized_name = FieldNameCapitalized(descriptor);
  (*variables)["capitalized_name"] = capitalized_name;
  (*variables)["raw_field_name"] = raw_field_name;
  (*variables)["field_number_name"] =
      classname + "_FieldNumber_" + capitalized_name;
  (*variables)["field_number"] = SimpleItoa(descriptor->number());
  (*variables)["field_type"] = GetCapitalizedType(descriptor);
  (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor);
  std::vector<string> field_flags;
  if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated");
  if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired");
  if (descriptor->is_optional()) field_flags.push_back("GPBFieldOptional");
  if (descriptor->is_packed()) field_flags.push_back("GPBFieldPacked");

  // ObjC custom flags.
  if (descriptor->has_default_value())
    field_flags.push_back("GPBFieldHasDefaultValue");
  if (needs_custom_name) field_flags.push_back("GPBFieldTextFormatNameCustom");
  if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
    field_flags.push_back("GPBFieldHasEnumDescriptor");
  }

  (*variables)["fieldflags"] = BuildFlagsString(FLAGTYPE_FIELD, field_flags);

  (*variables)["default"] = DefaultValue(descriptor);
  (*variables)["default_name"] = GPBGenericValueFieldName(descriptor);

  (*variables)["dataTypeSpecific_name"] = "className";
  (*variables)["dataTypeSpecific_value"] = "NULL";

  (*variables)["storage_offset_value"] =
      "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")";
  (*variables)["storage_offset_comment"] = "";

  // Clear some common things so they can be set just when needed.
  (*variables)["storage_attribute"] = "";
}

}  // namespace

FieldGenerator* FieldGenerator::Make(const FieldDescriptor* field,
                                     const Options& options) {
  FieldGenerator* result = NULL;
  if (field->is_repeated()) {
    switch (GetObjectiveCType(field)) {
      case OBJECTIVECTYPE_MESSAGE: {
        if (field->is_map()) {
          result = new MapFieldGenerator(field, options);
        } else {
          result = new RepeatedMessageFieldGenerator(field, options);
        }
        break;
      }
      case OBJECTIVECTYPE_ENUM:
        result = new RepeatedEnumFieldGenerator(field, options);
        break;
      default:
        result = new RepeatedPrimitiveFieldGenerator(field, options);
        break;
    }
  } else {
    switch (GetObjectiveCType(field)) {
      case OBJECTIVECTYPE_MESSAGE: {
        result = new MessageFieldGenerator(field, options);
        break;
      }
      case OBJECTIVECTYPE_ENUM:
        result = new EnumFieldGenerator(field, options);
        break;
      default:
        if (IsReferenceType(field)) {
          result = new PrimitiveObjFieldGenerator(field, options);
        } else {
          result = new PrimitiveFieldGenerator(field, options);
        }
        break;
    }
  }
  result->FinishInitialization();
  return result;
}

FieldGenerator::FieldGenerator(const FieldDescriptor* descriptor,
                               const Options& options)
    : descriptor_(descriptor) {
  SetCommonFieldVariables(descriptor, &variables_);
}

FieldGenerator::~FieldGenerator() {}

void FieldGenerator::GenerateFieldNumberConstant(io::Printer* printer) const {
  printer->Print(
      variables_,
      "$field_number_name$ = $field_number$,\n");
}

void FieldGenerator::GenerateCFunctionDeclarations(
    io::Printer* printer) const {
  // Nothing
}

void FieldGenerator::GenerateCFunctionImplementations(
    io::Printer* printer) const {
  // Nothing
}

void FieldGenerator::DetermineForwardDeclarations(
    std::set<string>* fwd_decls) const {
  // Nothing
}

void FieldGenerator::GenerateFieldDescription(
    io::Printer* printer, bool include_default) const {
  // Printed in the same order as the structure decl.
  if (include_default) {
    printer->Print(
        variables_,
        "{\n"
        "  .defaultValue.$default_name$ = $default$,\n"
        "  .core.name = \"$name$\",\n"
        "  .core.dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"
        "  .core.number = $field_number_name$,\n"
        "  .core.hasIndex = $has_index$,\n"
        "  .core.offset = $storage_offset_value$,$storage_offset_comment$\n"
        "  .core.flags = $fieldflags$,\n"
        "  .core.dataType = GPBDataType$field_type$,\n"
        "},\n");
  } else {
    printer->Print(
        variables_,
        "{\n"
        "  .name = \"$name$\",\n"
        "  .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"
        "  .number = $field_number_name$,\n"
        "  .hasIndex = $has_index$,\n"
        "  .offset = $storage_offset_value$,$storage_offset_comment$\n"
        "  .flags = $fieldflags$,\n"
        "  .dataType = GPBDataType$field_type$,\n"
        "},\n");
  }
}

void FieldGenerator::SetRuntimeHasBit(int has_index) {
  variables_["has_index"] = SimpleItoa(has_index);
}

void FieldGenerator::SetNoHasBit(void) {
  variables_["has_index"] = "GPBNoHasBit";
}

int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const {
  return 0;
}

void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) {
  // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
  // error cases, so it seems to be ok to use as a back door for errors.
  std::cerr << "Error: should have overridden SetExtraRuntimeHasBitsBase()." << std::endl;
  std::cerr.flush();
  abort();
}

void FieldGenerator::SetOneofIndexBase(int index_base) {
  if (descriptor_->containing_oneof() != NULL) {
    int index = descriptor_->containing_oneof()->index() + index_base;
    // Flip the sign to mark it as a oneof.
    variables_["has_index"] = SimpleItoa(-index);
  }
}

void FieldGenerator::FinishInitialization(void) {
  // If "property_type" wasn't set, make it "storage_type".
  if ((variables_.find("property_type") == variables_.end()) &&
      (variables_.find("storage_type") != variables_.end())) {
    variables_["property_type"] = variable("storage_type");
  }
}

SingleFieldGenerator::SingleFieldGenerator(const FieldDescriptor* descriptor,
                                           const Options& options)
    : FieldGenerator(descriptor, options) {
  // Nothing
}

SingleFieldGenerator::~SingleFieldGenerator() {}

void SingleFieldGenerator::GenerateFieldStorageDeclaration(
    io::Printer* printer) const {
  printer->Print(variables_, "$storage_type$ $name$;\n");
}

void SingleFieldGenerator::GeneratePropertyDeclaration(
    io::Printer* printer) const {
  printer->Print(variables_, "$comments$");
  printer->Print(
      variables_,
      "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n"
      "\n");
  if (WantsHasProperty()) {
    printer->Print(
        variables_,
        "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
  }
}

void SingleFieldGenerator::GeneratePropertyImplementation(
    io::Printer* printer) const {
  if (WantsHasProperty()) {
    printer->Print(variables_, "@dynamic has$capitalized_name$, $name$;\n");
  } else {
    printer->Print(variables_, "@dynamic $name$;\n");
  }
}

bool SingleFieldGenerator::WantsHasProperty(void) const {
  if (descriptor_->containing_oneof() != NULL) {
    // If in a oneof, it uses the oneofcase instead of a has bit.
    return false;
  }
  if (HasFieldPresence(descriptor_->file())) {
    // In proto1/proto2, every field has a has_$name$() method.
    return true;
  }
  return false;
}

bool SingleFieldGenerator::RuntimeUsesHasBit(void) const {
  if (descriptor_->containing_oneof() != NULL) {
    // The oneof tracks what is set instead.
    return false;
  }
  return true;
}

ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor,
                                             const Options& options)
    : SingleFieldGenerator(descriptor, options) {
  variables_["property_storage_attribute"] = "strong";
  if (IsRetainedName(variables_["name"])) {
    variables_["storage_attribute"] = " NS_RETURNS_NOT_RETAINED";
  }
}

ObjCObjFieldGenerator::~ObjCObjFieldGenerator() {}

void ObjCObjFieldGenerator::GenerateFieldStorageDeclaration(
    io::Printer* printer) const {
  printer->Print(variables_, "$storage_type$ *$name$;\n");
}

void ObjCObjFieldGenerator::GeneratePropertyDeclaration(
    io::Printer* printer) const {

  // Differs from SingleFieldGenerator::GeneratePropertyDeclaration() in that
  // it uses pointers and deals with Objective C's rules around storage name
  // conventions (init*, new*, etc.)

  printer->Print(variables_, "$comments$");
  printer->Print(
      variables_,
      "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n");
  if (WantsHasProperty()) {
    printer->Print(
        variables_,
        "/** Test to see if @c $name$ has been set. */\n"
        "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n");
  }
  if (IsInitName(variables_.find("name")->second)) {
    // If property name starts with init we need to annotate it to get past ARC.
    // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
    printer->Print(variables_,
                   "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n");
  }
  printer->Print("\n");
}

RepeatedFieldGenerator::RepeatedFieldGenerator(
    const FieldDescriptor* descriptor, const Options& options)
    : ObjCObjFieldGenerator(descriptor, options) {
  // Default to no comment and let the cases needing it fill it in.
  variables_["array_comment"] = "";
}

RepeatedFieldGenerator::~RepeatedFieldGenerator() {}

void RepeatedFieldGenerator::FinishInitialization(void) {
  FieldGenerator::FinishInitialization();
  if (variables_.find("array_property_type") == variables_.end()) {
    variables_["array_property_type"] = variable("array_storage_type");
  }
}

void RepeatedFieldGenerator::GenerateFieldStorageDeclaration(
    io::Printer* printer) const {
  printer->Print(variables_, "$array_storage_type$ *$name$;\n");
}

void RepeatedFieldGenerator::GeneratePropertyImplementation(
    io::Printer* printer) const {
  printer->Print(variables_, "@dynamic $name$, $name$_Count;\n");
}

void RepeatedFieldGenerator::GeneratePropertyDeclaration(
    io::Printer* printer) const {

  // Repeated fields don't need the has* properties, but they do expose a
  // *Count (to check without autocreation).  So for the field property we need
  // the same logic as ObjCObjFieldGenerator::GeneratePropertyDeclaration() for
  // dealing with needing Objective C's rules around storage name conventions
  // (init*, new*, etc.)

  printer->Print(
      variables_,
      "$comments$"
      "$array_comment$"
      "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"
      "/** The number of items in @c $name$ without causing the array to be created. */\n"
      "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n");
  if (IsInitName(variables_.find("name")->second)) {
    // If property name starts with init we need to annotate it to get past ARC.
    // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227
    printer->Print(variables_,
                   "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n");
  }
  printer->Print("\n");
}

bool RepeatedFieldGenerator::WantsHasProperty(void) const {
  // Consumer check the array size/existance rather than a has bit.
  return false;
}

bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const {
  return false;  // The array having anything is what is used.
}

FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
                                     const Options& options)
    : descriptor_(descriptor),
      field_generators_(
          new scoped_ptr<FieldGenerator>[descriptor->field_count()]),
      extension_generators_(
          new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
  // Construct all the FieldGenerators.
  for (int i = 0; i < descriptor->field_count(); i++) {
    field_generators_[i].reset(
        FieldGenerator::Make(descriptor->field(i), options));
  }
  for (int i = 0; i < descriptor->extension_count(); i++) {
    extension_generators_[i].reset(
        FieldGenerator::Make(descriptor->extension(i), options));
  }
}

FieldGeneratorMap::~FieldGeneratorMap() {}

const FieldGenerator& FieldGeneratorMap::get(
    const FieldDescriptor* field) const {
  GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
  return *field_generators_[field->index()];
}

const FieldGenerator& FieldGeneratorMap::get_extension(int index) const {
  return *extension_generators_[index];
}

int FieldGeneratorMap::CalculateHasBits(void) {
  int total_bits = 0;
  for (int i = 0; i < descriptor_->field_count(); i++) {
    if (field_generators_[i]->RuntimeUsesHasBit()) {
      field_generators_[i]->SetRuntimeHasBit(total_bits);
      ++total_bits;
    } else {
      field_generators_[i]->SetNoHasBit();
    }
    int extra_bits = field_generators_[i]->ExtraRuntimeHasBitsNeeded();
    if (extra_bits) {
      field_generators_[i]->SetExtraRuntimeHasBitsBase(total_bits);
      total_bits += extra_bits;
    }
  }
  return total_bits;
}

void FieldGeneratorMap::SetOneofIndexBase(int index_base) {
  for (int i = 0; i < descriptor_->field_count(); i++) {
    field_generators_[i]->SetOneofIndexBase(index_base);
  }
}

bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const {
  for (int i = 0; i < descriptor_->field_count(); i++) {
    if (HasNonZeroDefaultValue(descriptor_->field(i))) {
      return true;
    }
  }

  return false;
}

}  // namespace objectivec
}  // namespace compiler
}  // namespace protobuf
}  // namespace google