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/util/internal/protostream_objectsource.h>

#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <sstream>

#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/any.pb.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/util/internal/expecting_objectwriter.h>
#include <google/protobuf/util/internal/testdata/anys.pb.h>
#include <google/protobuf/util/internal/testdata/books.pb.h>
#include <google/protobuf/util/internal/testdata/field_mask.pb.h>
#include <google/protobuf/util/internal/testdata/maps.pb.h>
#include <google/protobuf/util/internal/testdata/proto3.pb.h>
#include <google/protobuf/util/internal/testdata/struct.pb.h>
#include <google/protobuf/util/internal/testdata/timestamp_duration.pb.h>
#include <google/protobuf/util/internal/type_info_test_helper.h>
#include <google/protobuf/util/internal/constants.h>
#include <google/protobuf/stubs/strutil.h>
#include <gtest/gtest.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

using google::protobuf::Descriptor;
using google::protobuf::DescriptorPool;
using google::protobuf::FileDescriptorProto;
using google::protobuf::Message;
using google::protobuf::io::ArrayInputStream;
using google::protobuf::io::CodedInputStream;
using util::Status;
using google::protobuf::testing::AnyM;
using google::protobuf::testing::AnyOut;
using google::protobuf::testing::Author;
using google::protobuf::testing::BadAuthor;
using google::protobuf::testing::BadNestedBook;
using google::protobuf::testing::Book;
using google::protobuf::testing::Book_Label;
using google::protobuf::testing::Cyclic;
using google::protobuf::testing::FieldMaskTest;
using google::protobuf::testing::MapOut;
using google::protobuf::testing::MapOutWireFormat;
using google::protobuf::testing::NestedBook;
using google::protobuf::testing::NestedFieldMask;
using google::protobuf::testing::PackedPrimitive;
using google::protobuf::testing::Primitive;
using google::protobuf::testing::Proto3Message;
using google::protobuf::testing::StructType;
using google::protobuf::testing::TimestampDuration;
using ::testing::_;

namespace {
string GetTypeUrl(const Descriptor* descriptor) {
  return string(kTypeServiceBaseUrl) + "/" + descriptor->full_name();
}
}  // namespace

class ProtostreamObjectSourceTest
    : public ::testing::TestWithParam<testing::TypeInfoSource> {
 protected:
  ProtostreamObjectSourceTest()
      : helper_(GetParam()),
        mock_(),
        ow_(&mock_),
        use_lower_camel_for_enums_(false),
        use_ints_for_enums_(false),
        add_trailing_zeros_(false),
        render_unknown_enum_values_(true) {
    helper_.ResetTypeInfo(Book::descriptor(), Proto3Message::descriptor());
  }

  virtual ~ProtostreamObjectSourceTest() {}

  void DoTest(const Message& msg, const Descriptor* descriptor) {
    Status status = ExecuteTest(msg, descriptor);
    EXPECT_EQ(util::Status(), status);
  }

  Status ExecuteTest(const Message& msg, const Descriptor* descriptor) {
    std::ostringstream oss;
    msg.SerializePartialToOstream(&oss);
    string proto = oss.str();
    ArrayInputStream arr_stream(proto.data(), proto.size());
    CodedInputStream in_stream(&arr_stream);

    google::protobuf::scoped_ptr<ProtoStreamObjectSource> os(
        helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor)));
    if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true);
    if (use_ints_for_enums_) os->set_use_ints_for_enums(true);
    os->set_max_recursion_depth(64);
    return os->WriteTo(&mock_);
  }

  void PrepareExpectingObjectWriterForRepeatedPrimitive() {
    ow_.StartObject("")
        ->StartList("repFix32")
        ->RenderUint32("", bit_cast<uint32>(3201))
        ->RenderUint32("", bit_cast<uint32>(0))
        ->RenderUint32("", bit_cast<uint32>(3202))
        ->EndList()
        ->StartList("repU32")
        ->RenderUint32("", bit_cast<uint32>(3203))
        ->RenderUint32("", bit_cast<uint32>(0))
        ->EndList()
        ->StartList("repI32")
        ->RenderInt32("", 0)
        ->RenderInt32("", 3204)
        ->RenderInt32("", 3205)
        ->EndList()
        ->StartList("repSf32")
        ->RenderInt32("", 3206)
        ->RenderInt32("", 0)
        ->EndList()
        ->StartList("repS32")
        ->RenderInt32("", 0)
        ->RenderInt32("", 3207)
        ->RenderInt32("", 3208)
        ->EndList()
        ->StartList("repFix64")
        ->RenderUint64("", bit_cast<uint64>(6401LL))
        ->RenderUint64("", bit_cast<uint64>(0LL))
        ->EndList()
        ->StartList("repU64")
        ->RenderUint64("", bit_cast<uint64>(0LL))
        ->RenderUint64("", bit_cast<uint64>(6402LL))
        ->RenderUint64("", bit_cast<uint64>(6403LL))
        ->EndList()
        ->StartList("repI64")
        ->RenderInt64("", 6404L)
        ->RenderInt64("", 0L)
        ->EndList()
        ->StartList("repSf64")
        ->RenderInt64("", 0L)
        ->RenderInt64("", 6405L)
        ->RenderInt64("", 6406L)
        ->EndList()
        ->StartList("repS64")
        ->RenderInt64("", 6407L)
        ->RenderInt64("", 0L)
        ->EndList()
        ->StartList("repFloat")
        ->RenderFloat("", 0.0f)
        ->RenderFloat("", 32.1f)
        ->RenderFloat("", 32.2f)
        ->EndList()
        ->StartList("repDouble")
        ->RenderDouble("", 64.1L)
        ->RenderDouble("", 0.0L)
        ->EndList()
        ->StartList("repBool")
        ->RenderBool("", true)
        ->RenderBool("", false)
        ->EndList()
        ->EndObject();
  }

  Primitive PrepareRepeatedPrimitive() {
    Primitive primitive;
    primitive.add_rep_fix32(3201);
    primitive.add_rep_fix32(0);
    primitive.add_rep_fix32(3202);
    primitive.add_rep_u32(3203);
    primitive.add_rep_u32(0);
    primitive.add_rep_i32(0);
    primitive.add_rep_i32(3204);
    primitive.add_rep_i32(3205);
    primitive.add_rep_sf32(3206);
    primitive.add_rep_sf32(0);
    primitive.add_rep_s32(0);
    primitive.add_rep_s32(3207);
    primitive.add_rep_s32(3208);
    primitive.add_rep_fix64(6401L);
    primitive.add_rep_fix64(0L);
    primitive.add_rep_u64(0L);
    primitive.add_rep_u64(6402L);
    primitive.add_rep_u64(6403L);
    primitive.add_rep_i64(6404L);
    primitive.add_rep_i64(0L);
    primitive.add_rep_sf64(0L);
    primitive.add_rep_sf64(6405L);
    primitive.add_rep_sf64(6406L);
    primitive.add_rep_s64(6407L);
    primitive.add_rep_s64(0L);
    primitive.add_rep_float(0.0f);
    primitive.add_rep_float(32.1f);
    primitive.add_rep_float(32.2f);
    primitive.add_rep_double(64.1L);
    primitive.add_rep_double(0.0);
    primitive.add_rep_bool(true);
    primitive.add_rep_bool(false);

    PrepareExpectingObjectWriterForRepeatedPrimitive();
    return primitive;
  }

  PackedPrimitive PreparePackedPrimitive() {
    PackedPrimitive primitive;
    primitive.add_rep_fix32(3201);
    primitive.add_rep_fix32(0);
    primitive.add_rep_fix32(3202);
    primitive.add_rep_u32(3203);
    primitive.add_rep_u32(0);
    primitive.add_rep_i32(0);
    primitive.add_rep_i32(3204);
    primitive.add_rep_i32(3205);
    primitive.add_rep_sf32(3206);
    primitive.add_rep_sf32(0);
    primitive.add_rep_s32(0);
    primitive.add_rep_s32(3207);
    primitive.add_rep_s32(3208);
    primitive.add_rep_fix64(6401L);
    primitive.add_rep_fix64(0L);
    primitive.add_rep_u64(0L);
    primitive.add_rep_u64(6402L);
    primitive.add_rep_u64(6403L);
    primitive.add_rep_i64(6404L);
    primitive.add_rep_i64(0L);
    primitive.add_rep_sf64(0L);
    primitive.add_rep_sf64(6405L);
    primitive.add_rep_sf64(6406L);
    primitive.add_rep_s64(6407L);
    primitive.add_rep_s64(0L);
    primitive.add_rep_float(0.0f);
    primitive.add_rep_float(32.1f);
    primitive.add_rep_float(32.2f);
    primitive.add_rep_double(64.1L);
    primitive.add_rep_double(0.0);
    primitive.add_rep_bool(true);
    primitive.add_rep_bool(false);

    PrepareExpectingObjectWriterForRepeatedPrimitive();
    return primitive;
  }

  void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; }

  void UseIntsForEnums() { use_ints_for_enums_ = true; }

  void AddTrailingZeros() { add_trailing_zeros_ = true; }

  void SetRenderUnknownEnumValues(bool value) {
    render_unknown_enum_values_ = value;
  }

  testing::TypeInfoTestHelper helper_;

  ::testing::NiceMock<MockObjectWriter> mock_;
  ExpectingObjectWriter ow_;
  bool use_lower_camel_for_enums_;
  bool use_ints_for_enums_;
  bool add_trailing_zeros_;
  bool render_unknown_enum_values_;
};

INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
                        ProtostreamObjectSourceTest,
                        ::testing::Values(
                            testing::USE_TYPE_RESOLVER));

TEST_P(ProtostreamObjectSourceTest, EmptyMessage) {
  Book empty;
  ow_.StartObject("")->EndObject();
  DoTest(empty, Book::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, Primitives) {
  Primitive primitive;
  primitive.set_fix32(3201);
  primitive.set_u32(3202);
  primitive.set_i32(3203);
  primitive.set_sf32(3204);
  primitive.set_s32(3205);
  primitive.set_fix64(6401L);
  primitive.set_u64(6402L);
  primitive.set_i64(6403L);
  primitive.set_sf64(6404L);
  primitive.set_s64(6405L);
  primitive.set_str("String Value");
  primitive.set_bytes("Some Bytes");
  primitive.set_float_(32.1f);
  primitive.set_double_(64.1L);
  primitive.set_bool_(true);

  ow_.StartObject("")
      ->RenderUint32("fix32", bit_cast<uint32>(3201))
      ->RenderUint32("u32", bit_cast<uint32>(3202))
      ->RenderInt32("i32", 3203)
      ->RenderInt32("sf32", 3204)
      ->RenderInt32("s32", 3205)
      ->RenderUint64("fix64", bit_cast<uint64>(6401LL))
      ->RenderUint64("u64", bit_cast<uint64>(6402LL))
      ->RenderInt64("i64", 6403L)
      ->RenderInt64("sf64", 6404L)
      ->RenderInt64("s64", 6405L)
      ->RenderString("str", "String Value")
      ->RenderBytes("bytes", "Some Bytes")
      ->RenderFloat("float", 32.1f)
      ->RenderDouble("double", 64.1L)
      ->RenderBool("bool", true)
      ->EndObject();
  DoTest(primitive, Primitive::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) {
  Primitive primitive = PrepareRepeatedPrimitive();
  primitive.add_rep_str("String One");
  primitive.add_rep_str("String Two");
  primitive.add_rep_bytes("Some Bytes");

  ow_.StartList("repStr")
      ->RenderString("", "String One")
      ->RenderString("", "String Two")
      ->EndList()
      ->StartList("repBytes")
      ->RenderBytes("", "Some Bytes")
      ->EndList();
  DoTest(primitive, Primitive::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, CustomJsonName) {
  Author author;
  author.set_id(12345);

  ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject();
  DoTest(author, Author::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, NestedMessage) {
  Author* author = new Author();
  author->set_name("Tolstoy");
  Book book;
  book.set_title("My Book");
  book.set_allocated_author(author);

  ow_.StartObject("")
      ->RenderString("title", "My Book")
      ->StartObject("author")
      ->RenderString("name", "Tolstoy")
      ->EndObject()
      ->EndObject();
  DoTest(book, Book::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, RepeatingField) {
  Author author;
  author.set_alive(false);
  author.set_name("john");
  author.add_pseudonym("phil");
  author.add_pseudonym("bob");

  ow_.StartObject("")
      ->RenderBool("alive", false)
      ->RenderString("name", "john")
      ->StartList("pseudonym")
      ->RenderString("", "phil")
      ->RenderString("", "bob")
      ->EndList()
      ->EndObject();
  DoTest(author, Author::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, PackedRepeatingFields) {
  DoTest(PreparePackedPrimitive(), PackedPrimitive::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, NonPackedPackableFieldsActuallyPacked) {
  // Protostream is packed, but parse with non-packed Primitive.
  DoTest(PreparePackedPrimitive(), Primitive::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, PackedPackableFieldNotActuallyPacked) {
  // Protostream is not packed, but parse with PackedPrimitive.
  DoTest(PrepareRepeatedPrimitive(), PackedPrimitive::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, BadAuthor) {
  Author author;
  author.set_alive(false);
  author.set_name("john");
  author.set_id(1234L);
  author.add_pseudonym("phil");
  author.add_pseudonym("bob");

  ow_.StartObject("")
      ->StartList("alive")
      ->RenderBool("", false)
      ->EndList()
      ->StartList("name")
      ->RenderUint64("", static_cast<uint64>('j'))
      ->RenderUint64("", static_cast<uint64>('o'))
      ->RenderUint64("", static_cast<uint64>('h'))
      ->RenderUint64("", static_cast<uint64>('n'))
      ->EndList()
      ->RenderString("pseudonym", "phil")
      ->RenderString("pseudonym", "bob")
      ->EndObject();
  // Protostream created with Author, but parsed with BadAuthor.
  DoTest(author, BadAuthor::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, NestedBookToBadNestedBook) {
  Book* book = new Book();
  book->set_length(250);
  book->set_published(2014L);
  NestedBook nested;
  nested.set_allocated_book(book);

  ow_.StartObject("")
      ->StartList("book")
      ->RenderUint32("", 24)  // tag for field length (3 << 3)
      ->RenderUint32("", 250)
      ->RenderUint32("", 32)  // tag for field published (4 << 3)
      ->RenderUint32("", 2014)
      ->EndList()
      ->EndObject();
  // Protostream created with NestedBook, but parsed with BadNestedBook.
  DoTest(nested, BadNestedBook::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, BadNestedBookToNestedBook) {
  BadNestedBook nested;
  nested.add_book(1);
  nested.add_book(2);
  nested.add_book(3);
  nested.add_book(4);
  nested.add_book(5);
  nested.add_book(6);
  nested.add_book(7);

  ow_.StartObject("")->StartObject("book")->EndObject()->EndObject();
  // Protostream created with BadNestedBook, but parsed with NestedBook.
  DoTest(nested, NestedBook::descriptor());
}

TEST_P(ProtostreamObjectSourceTest,
       LongRepeatedListDoesNotBreakIntoMultipleJsonLists) {
  Book book;

  int repeat = 10000;
  for (int i = 0; i < repeat; ++i) {
    Book_Label* label = book.add_labels();
    label->set_key(StrCat("i", i));
    label->set_value(StrCat("v", i));
  }

  // Make sure StartList and EndList are called exactly once (see b/18227499 for
  // problems when this doesn't happen)
  EXPECT_CALL(mock_, StartList(_)).Times(1);
  EXPECT_CALL(mock_, EndList()).Times(1);

  DoTest(book, Book::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputTest) {
  Book book;
  book.set_type(Book::ACTION_AND_ADVENTURE);

  UseLowerCamelForEnums();

  ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject();
  DoTest(book, Book::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) {
  Book book;
  book.set_type(Book::ACTION_AND_ADVENTURE);
  ow_.StartObject("")
      ->RenderString("type", "ACTION_AND_ADVENTURE")
      ->EndObject();
  DoTest(book, Book::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, UseIntsForEnumsTest) {
  Book book;
  book.set_type(Book::ACTION_AND_ADVENTURE);

  UseIntsForEnums();

  ow_.StartObject("")->RenderInt32("type", 3)->EndObject();
  DoTest(book, Book::descriptor());
}

TEST_P(ProtostreamObjectSourceTest,
       UnknownEnumAreDroppedWhenRenderUnknownEnumValuesIsUnset) {
  Proto3Message message;
  message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234));

  SetRenderUnknownEnumValues(false);

  // Unknown enum values are not output.
  ow_.StartObject("")->EndObject();
  DoTest(message, Proto3Message::descriptor());
}

TEST_P(ProtostreamObjectSourceTest,
       UnknownEnumAreOutputWhenRenderUnknownEnumValuesIsSet) {
  Proto3Message message;
  message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234));

  SetRenderUnknownEnumValues(true);

  // Unknown enum values are output.
  ow_.StartObject("")->RenderInt32("enumValue", 1234)->EndObject();
  DoTest(message, Proto3Message::descriptor());
}

TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) {
  Cyclic cyclic;
  cyclic.set_m_int(123);

  Book* book = cyclic.mutable_m_book();
  book->set_title("book title");
  Cyclic* current = cyclic.mutable_m_cyclic();
  Author* current_author = cyclic.add_m_author();
  for (int i = 0; i < 63; ++i) {
    Author* next = current_author->add_friend_();
    next->set_id(i);
    next->set_name(StrCat("author_name_", i));
    next->set_alive(true);
    current_author = next;
  }

  // Recursive message with depth (65) > max (max is 64).
  for (int i = 0; i < 64; ++i) {
    Cyclic* next = current->mutable_m_cyclic();
    next->set_m_str(StrCat("count_", i));
    current = next;
  }

  Status status = ExecuteTest(cyclic, Cyclic::descriptor());
  EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
}

class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest {
 protected:
  ProtostreamObjectSourceMapsTest() {
    helper_.ResetTypeInfo(MapOut::descriptor());
  }
};

INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
                        ProtostreamObjectSourceMapsTest,
                        ::testing::Values(
                            testing::USE_TYPE_RESOLVER));

// Tests JSON map.
//
// This is the example expected output.
// {
//   "map1": {
//     "key1": {
//       "foo": "foovalue"
//     },
//     "key2": {
//       "foo": "barvalue"
//     }
//   },
//   "map2": {
//     "nestedself": {
//       "map1": {
//         "nested_key1": {
//           "foo": "nested_foo"
//         }
//       },
//       "bar": "nested_bar_string"
//     }
//   },
//   "map3": {
//     "111": "one one one"
//   },
//   "bar": "top bar"
// }
TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) {
  MapOut out;
  (*out.mutable_map1())["key1"].set_foo("foovalue");
  (*out.mutable_map1())["key2"].set_foo("barvalue");

  MapOut* nested_value = &(*out.mutable_map2())["nestedself"];
  (*nested_value->mutable_map1())["nested_key1"].set_foo("nested_foo");
  nested_value->set_bar("nested_bar_string");

  (*out.mutable_map3())[111] = "one one one";

  out.set_bar("top bar");

  ow_.StartObject("")
      ->StartObject("map1")
      ->StartObject("key1")
      ->RenderString("foo", "foovalue")
      ->EndObject()
      ->StartObject("key2")
      ->RenderString("foo", "barvalue")
      ->EndObject()
      ->StartObject("map2")
      ->StartObject("nestedself")
      ->StartObject("map1")
      ->StartObject("nested_key1")
      ->RenderString("foo", "nested_foo")
      ->EndObject()
      ->EndObject()
      ->RenderString("bar", "nested_bar_string")
      ->EndObject()
      ->EndObject()
      ->StartObject("map3")
      ->RenderString("111", "one one one")
      ->EndObject()
      ->EndObject()
      ->RenderString("bar", "top bar")
      ->EndObject();

  DoTest(out, MapOut::descriptor());
}

TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) {
  // MapOutWireFormat has the same wire representation with MapOut but uses
  // repeated message fields to represent map fields so we can intentionally
  // leave out the key field or the value field of a map entry.
  MapOutWireFormat out;
  // Create some map entries without keys. They will be rendered with the
  // default values ("" for strings, "0" for integers, etc.).
  // {
  //   "map1": {
  //     "": {
  //       "foo": "foovalue"
  //     }
  //   },
  //   "map2": {
  //     "": {
  //       "map1": {
  //         "nested_key1": {
  //           "foo": "nested_foo"
  //         }
  //       }
  //     }
  //   },
  //   "map3": {
  //     "0": "one one one"
  //   },
  //   "map4": {
  //     "false": "bool"
  //   }
  // }
  out.add_map1()->mutable_value()->set_foo("foovalue");
  MapOut* nested = out.add_map2()->mutable_value();
  (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo");
  out.add_map3()->set_value("one one one");
  out.add_map4()->set_value("bool");

  ow_.StartObject("")
      ->StartObject("map1")
      ->StartObject("")
      ->RenderString("foo", "foovalue")
      ->EndObject()
      ->EndObject()
      ->StartObject("map2")
      ->StartObject("")
      ->StartObject("map1")
      ->StartObject("nested_key1")
      ->RenderString("foo", "nested_foo")
      ->EndObject()
      ->EndObject()
      ->EndObject()
      ->EndObject()
      ->StartObject("map3")
      ->RenderString("0", "one one one")
      ->EndObject()
      ->StartObject("map4")
      ->RenderString("false", "bool")
      ->EndObject()
      ->EndObject();

  DoTest(out, MapOut::descriptor());
}

class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest {
 protected:
  ProtostreamObjectSourceAnysTest() {
    helper_.ResetTypeInfo(AnyOut::descriptor(),
                          google::protobuf::Any::descriptor());
  }
};

INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
                        ProtostreamObjectSourceAnysTest,
                        ::testing::Values(
                            testing::USE_TYPE_RESOLVER));

// Tests JSON any support.
//
// This is the example expected output.
// {
//   "any": {
//     "@type": "type.googleapis.com/google.protobuf.testing.AnyM"
//     "foo": "foovalue"
//   }
// }
TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) {
  AnyOut out;
  ::google::protobuf::Any* any = out.mutable_any();

  AnyM m;
  m.set_foo("foovalue");
  any->PackFrom(m);

  ow_.StartObject("")
      ->StartObject("any")
      ->RenderString("@type",
                     "type.googleapis.com/google.protobuf.testing.AnyM")
      ->RenderString("foo", "foovalue")
      ->EndObject()
      ->EndObject();

  DoTest(out, AnyOut::descriptor());
}

TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) {
  AnyOut out;
  ::google::protobuf::Any* any = out.mutable_any();
  any->set_type_url("type.googleapis.com/google.protobuf.Any");

  ::google::protobuf::Any nested_any;
  nested_any.set_type_url("type.googleapis.com/google.protobuf.testing.AnyM");

  AnyM m;
  m.set_foo("foovalue");
  nested_any.set_value(m.SerializeAsString());

  any->set_value(nested_any.SerializeAsString());

  ow_.StartObject("")
      ->StartObject("any")
      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
      ->StartObject("value")
      ->RenderString("@type",
                     "type.googleapis.com/google.protobuf.testing.AnyM")
      ->RenderString("foo", "foovalue")
      ->EndObject()
      ->EndObject()
      ->EndObject();

  DoTest(out, AnyOut::descriptor());
}

TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) {
  AnyOut out;
  ::google::protobuf::Any* any = out.mutable_any();
  any->set_type_url("type.googleapis.com/google.protobuf.Any");

  ::google::protobuf::Any nested_any;
  nested_any.set_type_url("type.googleapis.com/google.protobuf.Any");

  ::google::protobuf::Any second_nested_any;
  second_nested_any.set_type_url(
      "type.googleapis.com/google.protobuf.testing.AnyM");

  AnyM m;
  m.set_foo("foovalue");
  second_nested_any.set_value(m.SerializeAsString());
  nested_any.set_value(second_nested_any.SerializeAsString());
  any->set_value(nested_any.SerializeAsString());

  ow_.StartObject("")
      ->StartObject("any")
      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
      ->StartObject("value")
      ->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
      ->StartObject("value")
      ->RenderString("@type",
                     "type.googleapis.com/google.protobuf.testing.AnyM")
      ->RenderString("foo", "foovalue")
      ->EndObject()
      ->EndObject()
      ->EndObject()
      ->EndObject();

  DoTest(out, AnyOut::descriptor());
}

TEST_P(ProtostreamObjectSourceAnysTest, EmptyAnyOutputsEmptyObject) {
  AnyOut out;
  out.mutable_any();

  ow_.StartObject("")->StartObject("any")->EndObject()->EndObject();

  DoTest(out, AnyOut::descriptor());
}

TEST_P(ProtostreamObjectSourceAnysTest, EmptyWithTypeAndNoValueOutputsType) {
  AnyOut out;
  out.mutable_any()->set_type_url("foo.googleapis.com/my.Type");

  ow_.StartObject("")
      ->StartObject("any")
      ->RenderString("@type", "foo.googleapis.com/my.Type")
      ->EndObject()
      ->EndObject();

  DoTest(out, AnyOut::descriptor());
}

TEST_P(ProtostreamObjectSourceAnysTest, MissingTypeUrlError) {
  AnyOut out;
  ::google::protobuf::Any* any = out.mutable_any();

  AnyM m;
  m.set_foo("foovalue");
  any->set_value(m.SerializeAsString());

  // We start the "AnyOut" part and then fail when we hit the Any object.
  ow_.StartObject("");

  Status status = ExecuteTest(out, AnyOut::descriptor());
  EXPECT_EQ(util::error::INTERNAL, status.error_code());
}

TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeServiceError) {
  AnyOut out;
  ::google::protobuf::Any* any = out.mutable_any();
  any->set_type_url("foo.googleapis.com/my.own.Type");

  AnyM m;
  m.set_foo("foovalue");
  any->set_value(m.SerializeAsString());

  // We start the "AnyOut" part and then fail when we hit the Any object.
  ow_.StartObject("");

  Status status = ExecuteTest(out, AnyOut::descriptor());
  EXPECT_EQ(util::error::INTERNAL, status.error_code());
}

TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeError) {
  AnyOut out;
  ::google::protobuf::Any* any = out.mutable_any();
  any->set_type_url("type.googleapis.com/unknown.Type");

  AnyM m;
  m.set_foo("foovalue");
  any->set_value(m.SerializeAsString());

  // We start the "AnyOut" part and then fail when we hit the Any object.
  ow_.StartObject("");

  Status status = ExecuteTest(out, AnyOut::descriptor());
  EXPECT_EQ(util::error::INTERNAL, status.error_code());
}

class ProtostreamObjectSourceStructTest : public ProtostreamObjectSourceTest {
 protected:
  ProtostreamObjectSourceStructTest() {
    helper_.ResetTypeInfo(StructType::descriptor(),
                          google::protobuf::Struct::descriptor());
  }
};

INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
                        ProtostreamObjectSourceStructTest,
                        ::testing::Values(
                            testing::USE_TYPE_RESOLVER));

// Tests struct
//
//  "object": {
//    "k1": 123,
//    "k2": true
//  }
TEST_P(ProtostreamObjectSourceStructTest, StructRenderSuccess) {
  StructType out;
  google::protobuf::Struct* s = out.mutable_object();
  s->mutable_fields()->operator[]("k1").set_number_value(123);
  s->mutable_fields()->operator[]("k2").set_bool_value(true);

  ow_.StartObject("")
      ->StartObject("object")
      ->RenderDouble("k1", 123)
      ->RenderBool("k2", true)
      ->EndObject()
      ->EndObject();

  DoTest(out, StructType::descriptor());
}

TEST_P(ProtostreamObjectSourceStructTest, MissingValueSkipsField) {
  StructType out;
  google::protobuf::Struct* s = out.mutable_object();
  s->mutable_fields()->operator[]("k1");

  ow_.StartObject("")->StartObject("object")->EndObject()->EndObject();

  DoTest(out, StructType::descriptor());
}

class ProtostreamObjectSourceFieldMaskTest
    : public ProtostreamObjectSourceTest {
 protected:
  ProtostreamObjectSourceFieldMaskTest() {
    helper_.ResetTypeInfo(FieldMaskTest::descriptor(),
                          google::protobuf::FieldMask::descriptor());
  }
};

INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
                        ProtostreamObjectSourceFieldMaskTest,
                        ::testing::Values(
                            testing::USE_TYPE_RESOLVER));

TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) {
  FieldMaskTest out;
  out.set_id("1");
  out.mutable_single_mask()->add_paths("path1");
  out.mutable_single_mask()->add_paths("snake_case_path2");
  ::google::protobuf::FieldMask* mask = out.add_repeated_mask();
  mask->add_paths("path3");
  mask = out.add_repeated_mask();
  mask->add_paths("snake_case_path4");
  mask->add_paths("path5");
  NestedFieldMask* nested = out.add_nested_mask();
  nested->set_data("data");
  nested->mutable_single_mask()->add_paths("nested.path1");
  nested->mutable_single_mask()->add_paths("nested_field.snake_case_path2");
  mask = nested->add_repeated_mask();
  mask->add_paths("nested_field.path3");
  mask->add_paths("nested.snake_case_path4");
  mask = nested->add_repeated_mask();
  mask->add_paths("nested.path5");
  mask = nested->add_repeated_mask();
  mask->add_paths(
      "snake_case.map_field[\"map_key_should_be_ignored\"].nested_snake_case."
      "map_field[\"map_key_sho\\\"uld_be_ignored\"]");

  ow_.StartObject("")
      ->RenderString("id", "1")
      ->RenderString("singleMask", "path1,snakeCasePath2")
      ->StartList("repeatedMask")
      ->RenderString("", "path3")
      ->RenderString("", "snakeCasePath4,path5")
      ->EndList()
      ->StartList("nestedMask")
      ->StartObject("")
      ->RenderString("data", "data")
      ->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2")
      ->StartList("repeatedMask")
      ->RenderString("", "nestedField.path3,nested.snakeCasePath4")
      ->RenderString("", "nested.path5")
      ->RenderString("",
                     "snakeCase.mapField[\"map_key_should_be_ignored\"]."
                     "nestedSnakeCase.mapField[\"map_key_sho\\\"uld_be_"
                     "ignored\"]")
      ->EndList()
      ->EndObject()
      ->EndList()
      ->EndObject();

  DoTest(out, FieldMaskTest::descriptor());
}

class ProtostreamObjectSourceTimestampTest
    : public ProtostreamObjectSourceTest {
 protected:
  ProtostreamObjectSourceTimestampTest() {
    helper_.ResetTypeInfo(TimestampDuration::descriptor());
  }
};

INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest,
                        ProtostreamObjectSourceTimestampTest,
                        ::testing::Values(
                            testing::USE_TYPE_RESOLVER));

TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) {
  TimestampDuration out;
  google::protobuf::Timestamp* ts = out.mutable_ts();
  // Min allowed seconds - 1
  ts->set_seconds(kTimestampMinSeconds - 1);
  ow_.StartObject("");

  Status status = ExecuteTest(out, TimestampDuration::descriptor());
  EXPECT_EQ(util::error::INTERNAL, status.error_code());
}

TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) {
  TimestampDuration out;
  google::protobuf::Timestamp* ts = out.mutable_ts();
  // Max allowed seconds + 1
  ts->set_seconds(kTimestampMaxSeconds + 1);
  ow_.StartObject("");

  Status status = ExecuteTest(out, TimestampDuration::descriptor());
  EXPECT_EQ(util::error::INTERNAL, status.error_code());
}

TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) {
  TimestampDuration out;
  google::protobuf::Duration* dur = out.mutable_dur();
  // Min allowed seconds - 1
  dur->set_seconds(kDurationMinSeconds - 1);
  ow_.StartObject("");

  Status status = ExecuteTest(out, TimestampDuration::descriptor());
  EXPECT_EQ(util::error::INTERNAL, status.error_code());
}

TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) {
  TimestampDuration out;
  google::protobuf::Duration* dur = out.mutable_dur();
  // Min allowed seconds + 1
  dur->set_seconds(kDurationMaxSeconds + 1);
  ow_.StartObject("");

  Status status = ExecuteTest(out, TimestampDuration::descriptor());
  EXPECT_EQ(util::error::INTERNAL, status.error_code());
}

TEST_P(ProtostreamObjectSourceTimestampTest, TimestampDurationDefaultValue) {
  TimestampDuration out;
  out.mutable_ts()->set_seconds(0);
  out.mutable_dur()->set_seconds(0);

  ow_.StartObject("")
      ->RenderString("ts", "1970-01-01T00:00:00Z")
      ->RenderString("dur", "0s")
      ->EndObject();

  DoTest(out, TimestampDuration::descriptor());
}

}  // namespace converter
}  // namespace util
}  // 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_UTIL_CONVERTER_MOCK_ERROR_LISTENER_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_MOCK_ERROR_LISTENER_H__

#include <google/protobuf/stubs/stringpiece.h>
#include <google/protobuf/util/internal/error_listener.h>
#include <google/protobuf/util/internal/location_tracker.h>
#include <gmock/gmock.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

class MockErrorListener : public ErrorListener {
 public:
  MockErrorListener() {}
  virtual ~MockErrorListener() {}

  MOCK_METHOD3(InvalidName, void(const LocationTrackerInterface& loc,
                                 StringPiece unknown_name,
                                 StringPiece message));
  MOCK_METHOD3(InvalidValue, void(const LocationTrackerInterface& loc,
                                  StringPiece type_name, StringPiece value));
  MOCK_METHOD2(MissingField, void(const LocationTrackerInterface& loc,
                                  StringPiece missing_name));
};

}  // namespace converter
}  // namespace util
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_MOCK_ERROR_LISTENER_H__

mime_type: text/plain


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_UTIL_CONVERTER_JSON_OBJECTWRITER_H__
#define GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_H__

#include <memory>
#ifndef _SHARED_PTR_H
#include <google/protobuf/stubs/shared_ptr.h>
#endif
#include <string>

#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/util/internal/structured_objectwriter.h>
#include <google/protobuf/stubs/bytestream.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

// An ObjectWriter implementation that outputs JSON. This ObjectWriter
// supports writing a compact form or a pretty printed form.
//
// Sample usage:
//   string output;
//   StringOutputStream* str_stream = new StringOutputStream(&output);
//   CodedOutputStream* out_stream = new CodedOutputStream(str_stream);
//   JsonObjectWriter* ow = new JsonObjectWriter("  ", out_stream);
//   ow->StartObject("")
//       ->RenderString("name", "value")
//       ->RenderString("emptystring", string())
//       ->StartObject("nested")
//         ->RenderInt64("light", 299792458);
//         ->RenderDouble("pi", 3.141592653589793);
//       ->EndObject()
//       ->StartList("empty")
//       ->EndList()
//     ->EndObject();
//
// And then the output string would become:
// {
//   "name": "value",
//   "emptystring": "",
//   "nested": {
//     "light": "299792458",
//     "pi": 3.141592653589793
//   },
//   "empty": []
// }
//
// JsonObjectWriter does not validate if calls actually result in valid JSON.
// For example, passing an empty name when one would be required won't result
// in an error, just an invalid output.
//
// Note that all int64 and uint64 are rendered as strings instead of numbers.
// This is because JavaScript parses numbers as 64-bit float thus int64 and
// uint64 would lose precision if rendered as numbers.
//
// JsonObjectWriter is thread-unsafe.
class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter {
 public:
  JsonObjectWriter(StringPiece indent_string,
                   google::protobuf::io::CodedOutputStream* out)
      : element_(new Element(NULL)),
        stream_(out),
        sink_(out),
        indent_string_(indent_string.ToString()),
        use_websafe_base64_for_bytes_(false),
        empty_name_ok_for_next_key_(false) {}
  virtual ~JsonObjectWriter();

  // ObjectWriter methods.
  virtual JsonObjectWriter* StartObject(StringPiece name);
  virtual JsonObjectWriter* EndObject();
  virtual JsonObjectWriter* StartList(StringPiece name);
  virtual JsonObjectWriter* EndList();
  virtual JsonObjectWriter* RenderBool(StringPiece name, bool value);
  virtual JsonObjectWriter* RenderInt32(StringPiece name, int32 value);
  virtual JsonObjectWriter* RenderUint32(StringPiece name, uint32 value);
  virtual JsonObjectWriter* RenderInt64(StringPiece name, int64 value);
  virtual JsonObjectWriter* RenderUint64(StringPiece name, uint64 value);
  virtual JsonObjectWriter* RenderDouble(StringPiece name, double value);
  virtual JsonObjectWriter* RenderFloat(StringPiece name, float value);
  virtual JsonObjectWriter* RenderString(StringPiece name, StringPiece value);
  virtual JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value);
  virtual JsonObjectWriter* RenderNull(StringPiece name);
  virtual JsonObjectWriter* RenderNullAsEmpty(StringPiece name);

  void set_use_websafe_base64_for_bytes(bool value) {
    use_websafe_base64_for_bytes_ = value;
  }

  // Whether empty strings should be rendered for the next JSON key. This
  // setting is only valid until the next key is rendered, after which it gets
  // reset to false.
  virtual void empty_name_ok_for_next_key() {
    empty_name_ok_for_next_key_ = true;
  }

 protected:
  class LIBPROTOBUF_EXPORT Element : public BaseElement {
   public:
    explicit Element(Element* parent) : BaseElement(parent), is_first_(true) {}

    // Called before each field of the Element is to be processed.
    // Returns true if this is the first call (processing the first field).
    bool is_first() {
      if (is_first_) {
        is_first_ = false;
        return true;
      }
      return false;
    }

   private:
    bool is_first_;

    GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(Element);
  };

  virtual Element* element() { return element_.get(); }

 private:
  class LIBPROTOBUF_EXPORT ByteSinkWrapper : public strings::ByteSink {
   public:
    explicit ByteSinkWrapper(google::protobuf::io::CodedOutputStream* stream)
        : stream_(stream) {}
    virtual ~ByteSinkWrapper() {}

    // ByteSink methods.
    virtual void Append(const char* bytes, size_t n) {
      stream_->WriteRaw(bytes, n);
    }

   private:
    google::protobuf::io::CodedOutputStream* stream_;

    GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ByteSinkWrapper);
  };

  // Renders a simple value as a string. By default all non-string Render
  // methods convert their argument to a string and call this method. This
  // method can then be used to render the simple value without escaping it.
  JsonObjectWriter* RenderSimple(StringPiece name, const string& value) {
    WritePrefix(name);
    stream_->WriteString(value);
    return this;
  }

  // Pushes a new element to the stack.
  void Push() { element_.reset(new Element(element_.release())); }

  // Pops an element off of the stack and deletes the popped element.
  void Pop() {
    bool needs_newline = !element_->is_first();
    element_.reset(element_->pop<Element>());
    if (needs_newline) NewLine();
  }

  // If pretty printing is enabled, this will write a newline to the output,
  // followed by optional indentation. Otherwise this method is a noop.
  void NewLine() {
    if (!indent_string_.empty()) {
      WriteChar('\n');
      for (int i = 0; i < element()->level(); i++) {
        stream_->WriteString(indent_string_);
      }
    }
  }

  // Writes a prefix. This will write out any pretty printing and
  // commas that are required, followed by the name and a ':' if
  // the name is not null.
  void WritePrefix(StringPiece name);

  // Writes an individual character to the output.
  void WriteChar(const char c) { stream_->WriteRaw(&c, sizeof(c)); }

  // Returns the current value of empty_name_ok_for_next_key_ and resets it to
  // false.
  bool GetAndResetEmptyKeyOk();

  google::protobuf::scoped_ptr<Element> element_;
  google::protobuf::io::CodedOutputStream* stream_;
  ByteSinkWrapper sink_;
  const string indent_string_;

  // Whether to use regular or websafe base64 encoding for byte fields. Defaults
  // to regular base64 encoding.
  bool use_websafe_base64_for_bytes_;

  // Whether empty strings should be rendered for the next JSON key. This
  // setting is only valid until the next key is rendered, after which it gets
  // reset to false.
  bool empty_name_ok_for_next_key_;

  GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter);
};

}  // namespace converter
}  // namespace util
}  // namespace protobuf

}  // namespace google
#endif  // GOOGLE_PROTOBUF_UTIL_CONVERTER_JSON_OBJECTWRITER_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 <google/protobuf/util/internal/protostream_objectwriter.h>

#include <functional>
#include <stack>

#include <google/protobuf/stubs/once.h>
#include <google/protobuf/stubs/time.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/util/internal/field_mask_utility.h>
#include <google/protobuf/util/internal/object_location_tracker.h>
#include <google/protobuf/util/internal/constants.h>
#include <google/protobuf/util/internal/utility.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/map_util.h>
#include <google/protobuf/stubs/statusor.h>

namespace google {
namespace protobuf {
namespace util {
namespace converter {

using google::protobuf::internal::WireFormatLite;
using util::error::INVALID_ARGUMENT;
using util::Status;
using util::StatusOr;

ProtoStreamObjectWriter::ProtoStreamObjectWriter(
    TypeResolver* type_resolver, const google::protobuf::Type& type,
    strings::ByteSink* output, ErrorListener* listener,
    const ProtoStreamObjectWriter::Options& options)
    : ProtoWriter(type_resolver, type, output, listener),
      master_type_(type),
      current_(NULL),
      options_(options) {
  set_ignore_unknown_fields(options_.ignore_unknown_fields);
  set_use_lower_camel_for_enums(options_.use_lower_camel_for_enums);
}

ProtoStreamObjectWriter::ProtoStreamObjectWriter(
    const TypeInfo* typeinfo, const google::protobuf::Type& type,
    strings::ByteSink* output, ErrorListener* listener)
    : ProtoWriter(typeinfo, type, output, listener),
      master_type_(type),
      current_(NULL),
      options_(ProtoStreamObjectWriter::Options::Defaults()) {}

ProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
  if (current_ == NULL) return;
  // Cleanup explicitly in order to avoid destructor stack overflow when input
  // is deeply nested.
  // Cast to BaseElement to avoid doing additional checks (like missing fields)
  // during pop().
  google::protobuf::scoped_ptr<BaseElement> element(
      static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
  while (element != NULL) {
    element.reset(element->pop<BaseElement>());
  }
}

namespace {
// Utility method to split a string representation of Timestamp or Duration and
// return the parts.
void SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
                          StringPiece* nanos) {
  size_t idx = input.rfind('.');
  if (idx != string::npos) {
    *seconds = input.substr(0, idx);
    *nanos = input.substr(idx + 1);
  } else {
    *seconds = input;
    *nanos = StringPiece();
  }
}

Status GetNanosFromStringPiece(StringPiece s_nanos,
                               const char* parse_failure_message,
                               const char* exceeded_limit_message,
                               int32* nanos) {
  *nanos = 0;

  // Count the number of leading 0s and consume them.
  int num_leading_zeros = 0;
  while (s_nanos.Consume("0")) {
    num_leading_zeros++;
  }
  int32 i_nanos = 0;
  // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
  // "0." + s_nanos.ToString() seconds. An int32 is used for the
  // conversion to 'nanos', rather than a double, so that there is no
  // loss of precision.
  if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) {
    return Status(INVALID_ARGUMENT, parse_failure_message);
  }
  if (i_nanos > kNanosPerSecond || i_nanos < 0) {
    return Status(INVALID_ARGUMENT, exceeded_limit_message);
  }
  // s_nanos should only have digits. No whitespace.
  if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
    return Status(INVALID_ARGUMENT, parse_failure_message);
  }

  if (i_nanos > 0) {
    // 'scale' is the number of digits to the right of the decimal
    // point in "0." + s_nanos.ToString()
    int32 scale = num_leading_zeros + s_nanos.size();
    // 'conversion' converts i_nanos into nanoseconds.
    // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale))
    // For efficiency, we precompute the conversion factor.
    int32 conversion = 0;
    switch (scale) {
      case 1:
        conversion = 100000000;
        break;
      case 2:
        conversion = 10000000;
        break;
      case 3:
        conversion = 1000000;
        break;
      case 4:
        conversion = 100000;
        break;
      case 5:
        conversion = 10000;
        break;
      case 6:
        conversion = 1000;
        break;
      case 7:
        conversion = 100;
        break;
      case 8:
        conversion = 10;
        break;
      case 9:
        conversion = 1;
        break;
      default:
        return Status(INVALID_ARGUMENT, exceeded_limit_message);
    }
    *nanos = i_nanos * conversion;
  }

  return Status();
}

}  // namespace

ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
    : parent_(parent),
      ow_(),
      invalid_(false),
      data_(),
      output_(&data_),
      depth_(0),
      is_well_known_type_(false),
      well_known_type_render_(NULL) {}

ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {}

void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
  ++depth_;
  // If an object writer is absent, that means we have not called StartAny()
  // before reaching here, which happens when we have data before the "@type"
  // field.
  if (ow_ == NULL) {
    // Save data before the "@type" field for later replay.
    uninterpreted_events_.push_back(Event(Event::START_OBJECT, name));
  } else if (is_well_known_type_ && depth_ == 1) {
    // For well-known types, the only other field besides "@type" should be a
    // "value" field.
    if (name != "value" && !invalid_) {
      parent_->InvalidValue("Any",
                            "Expect a \"value\" field for well-known types.");
      invalid_ = true;
    }
    ow_->StartObject("");
  } else {
    // Forward the call to the child writer if:
    //   1. the type is not a well-known type.
    //   2. or, we are in a nested Any, Struct, or Value object.
    ow_->StartObject(name);
  }
}

bool ProtoStreamObjectWriter::AnyWriter::EndObject() {
  --depth_;
  if (ow_ == NULL) {
    if (depth_ >= 0) {
      // Save data before the "@type" field for later replay.
      uninterpreted_events_.push_back(Event(Event::END_OBJECT));
    }
  } else if (depth_ >= 0 || !is_well_known_type_) {
    // As long as depth_ >= 0, we know we haven't reached the end of Any.
    // Propagate these EndObject() calls to the contained ow_. For regular
    // message types, we propagate the end of Any as well.
    ow_->EndObject();
  }
  // A negative depth_ implies that we have reached the end of Any
  // object. Now we write out its contents.
  if (depth_ < 0) {
    WriteAny();
    return false;
  }
  return true;
}

void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) {
  ++depth_;
  if (ow_ == NULL) {
    // Save data before the "@type" field for later replay.
    uninterpreted_events_.push_back(Event(Event::START_LIST, name));
  } else if (is_well_known_type_ && depth_ == 1) {
    if (name != "value" && !invalid_) {
      parent_->InvalidValue("Any",
                            "Expect a \"value\" field for well-known types.");
      invalid_ = true;
    }
    ow_->StartList("");
  } else {
    ow_->StartList(name);
  }
}

void ProtoStreamObjectWriter::AnyWriter::EndList() {
  --depth_;
  if (depth_ < 0) {
    GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
    depth_ = 0;
  }
  if (ow_ == NULL) {
    // Save data before the "@type" field for later replay.
    uninterpreted_events_.push_back(Event(Event::END_LIST));
  } else {
    ow_->EndList();
  }
}

void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
    StringPiece name, const DataPiece& value) {
  // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type"
  // should go to the contained ow_ as they indicate nested Anys.
  if (depth_ == 0 && ow_ == NULL && name == "@type") {
    StartAny(value);
  } else if (ow_ == NULL) {
    // Save data before the "@type" field.
    uninterpreted_events_.push_back(Event(name, value));
  } else if (depth_ == 0 && is_well_known_type_) {
    if (name != "value" && !invalid_) {
      parent_->InvalidValue("Any",
                            "Expect a \"value\" field for well-known types.");
      invalid_ = true;
    }
    if (well_known_type_render_ == NULL) {
      // Only Any and Struct don't have a special type render but both of
      // them expect a JSON object (i.e., a StartObject() call).
      if (value.type() != DataPiece::TYPE_NULL && !invalid_) {
        parent_->InvalidValue("Any", "Expect a JSON object.");
        invalid_ = true;
      }
    } else {
      ow_->ProtoWriter::StartObject("");
      Status status = (*well_known_type_render_)(ow_.get(), value);
      if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
      ow_->ProtoWriter::EndObject();
    }
  } else {
    ow_->RenderDataPiece(name, value);
  }
}

void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
  // Figure out the type url. This is a copy-paste from WriteString but we also
  // need the value, so we can't just call through to that.
  if (value.type() == DataPiece::TYPE_STRING) {
    type_url_ = value.str().ToString();
  } else {
    StatusOr<string> s = value.ToString();
    if (!s.ok()) {
      parent_->InvalidValue("String", s.status().error_message());
      invalid_ = true;
      return;
    }
    type_url_ = s.ValueOrDie();
  }
  // Resolve the type url, and report an error if we failed to resolve it.
  StatusOr<const google::protobuf::Type*> resolved_type =
      parent_->typeinfo()->ResolveTypeUrl(type_url_);
  if (!resolved_type.ok()) {
    parent_->InvalidValue("Any", resolved_type.status().error_message());
    invalid_ = true;
    return;
  }
  // At this point, type is never null.
  const google::protobuf::Type* type = resolved_type.ValueOrDie();

  well_known_type_render_ = FindTypeRenderer(type_url_);
  if (well_known_type_render_ != NULL ||
      // Explicitly list Any and Struct here because they don't have a
      // custom renderer.
      type->name() == kAnyType || type->name() == kStructType) {
    is_well_known_type_ = true;
  }

  // Create our object writer and initialize it with the first StartObject
  // call.
  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
                                        parent_->listener()));

  // Don't call StartObject() for well-known types yet. Depending on the
  // type of actual data, we may not need to call StartObject(). For
  // example:
  // {
  //   "@type": "type.googleapis.com/google.protobuf.Value",
  //   "value": [1, 2, 3],
  // }
  // With the above JSON representation, we will only call StartList() on the
  // contained ow_.
  if (!is_well_known_type_) {
    ow_->StartObject("");
  }

  // Now we know the proto type and can interpret all data fields we gathered
  // before the "@type" field.
  for (int i = 0; i < uninterpreted_events_.size(); ++i) {
    uninterpreted_events_[i].Replay(this);
  }
}

void ProtoStreamObjectWriter::AnyWriter::WriteAny() {
  if (ow_ == NULL) {
    if (uninterpreted_events_.empty()) {
      // We never got any content, so just return immediately, which is
      // equivalent to writing an empty Any.
      return;
    } else {
      // There are uninterpreted data, but we never got a "@type" field.
      if (!invalid_) {
        parent_->InvalidValue("Any", StrCat("Missing @type for any field in ",
                                            parent_->master_type_.name()));
        invalid_ = true;
      }
      return;
    }
  }
  // Render the type_url and value fields directly to the stream.
  // type_url has tag 1 and value has tag 2.
  WireFormatLite::WriteString(1, type_url_, parent_->stream());
  if (!data_.empty()) {
    WireFormatLite::WriteBytes(2, data_, parent_->stream());
  }
}

void ProtoStreamObjectWriter::AnyWriter::Event::Replay(
    AnyWriter* writer) const {
  switch (type_) {
    case START_OBJECT:
      writer->StartObject(name_);
      break;
    case END_OBJECT:
      writer->EndObject();
      break;
    case START_LIST:
      writer->StartList(name_);
      break;
    case END_LIST:
      writer->EndList();
      break;
    case RENDER_DATA_PIECE:
      writer->RenderDataPiece(name_, value_);
      break;
  }
}

void ProtoStreamObjectWriter::AnyWriter::Event::DeepCopy() {
  // DataPiece only contains a string reference. To make sure the referenced
  // string value stays valid, we make a copy of the string value and update
  // DataPiece to reference our own copy.
  if (value_.type() == DataPiece::TYPE_STRING) {
    StrAppend(&value_storage_, value_.str());
    value_ = DataPiece(value_storage_, value_.use_strict_base64_decoding());
  } else if (value_.type() == DataPiece::TYPE_BYTES) {
    value_storage_ = value_.ToBytes().ValueOrDie();
    value_ =
        DataPiece(value_storage_, true, value_.use_strict_base64_decoding());
  }
}

ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
                                    ItemType item_type, bool is_placeholder,
                                    bool is_list)
    : BaseElement(NULL),
      ow_(enclosing),
      any_(),
      item_type_(item_type),
      is_placeholder_(is_placeholder),
      is_list_(is_list) {
  if (item_type_ == ANY) {
    any_.reset(new AnyWriter(ow_));
  }
  if (item_type == MAP) {
    map_keys_.reset(new hash_set<string>);
  }
}

ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
                                    ItemType item_type, bool is_placeholder,
                                    bool is_list)
    : BaseElement(parent),
      ow_(this->parent()->ow_),
      any_(),
      item_type_(item_type),
      is_placeholder_(is_placeholder),
      is_list_(is_list) {
  if (item_type == ANY) {
    any_.reset(new AnyWriter(ow_));
  }
  if (item_type == MAP) {
    map_keys_.reset(new hash_set<string>);
  }
}

bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
    StringPiece map_key) {
  return InsertIfNotPresent(map_keys_.get(), map_key.ToString());
}

ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
    StringPiece name) {
  if (invalid_depth() > 0) {
    IncrementInvalidDepth();
    return this;
  }

  // Starting the root message. Create the root Item and return.
  // ANY message type does not need special handling, just set the ItemType
  // to ANY.
  if (current_ == NULL) {
    ProtoWriter::StartObject(name);
    current_.reset(new Item(
        this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE,
        false, false));

    // If master type is a special type that needs extra values to be written to
    // stream, we write those values.
    if (master_type_.name() == kStructType) {
      // Struct has a map<string, Value> field called "fields".
      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
      // "fields": [
      Push("fields", Item::MAP, true, true);
      return this;
    }

    if (master_type_.name() == kStructValueType) {
      // We got a StartObject call with google.protobuf.Value field. The only
      // object within that type is a struct type. So start a struct.
      //
      // The struct field in Value type is named "struct_value"
      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
      // Also start the map field "fields" within the struct.
      // "struct_value": {
      //   "fields": [
      Push("struct_value", Item::MESSAGE, true, false);
      Push("fields", Item::MAP, true, true);
      return this;
    }

    if (master_type_.name() == kStructListValueType) {
      InvalidValue(kStructListValueType,
                   "Cannot start root message with ListValue.");
    }

    return this;
  }

  // Send all ANY events to AnyWriter.
  if (current_->IsAny()) {
    current_->any()->StartObject(name);
    return this;
  }

  // If we are within a map, we render name as keys and send StartObject to the
  // value field.
  if (current_->IsMap()) {
    if (!ValidMapKey(name)) {
      IncrementInvalidDepth();
      return this;
    }

    // Map is a repeated field of message type with a "key" and a "value" field.
    // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
    // message MapFieldEntry {
    //   key_type key = 1;
    //   value_type value = 2;
    // }
    //
    // repeated MapFieldEntry map_field = N;
    //
    // That means, we render the following element within a list (hence no
    // name):
    // { "key": "<name>", "value": {
    Push("", Item::MESSAGE, false, false);
    ProtoWriter::RenderDataPiece("key",
                                 DataPiece(name, use_strict_base64_decoding()));
    Push("value", Item::MESSAGE, true, false);

    // Make sure we are valid so far after starting map fields.
    if (invalid_depth() > 0) return this;

    // If top of stack is g.p.Struct type, start the struct the map field within
    // it.
    if (element() != NULL && IsStruct(*element()->parent_field())) {
      // Render "fields": [
      Push("fields", Item::MAP, true, true);
      return this;
    }

    // If top of stack is g.p.Value type, start the Struct within it.
    if (element() != NULL && IsStructValue(*element()->parent_field())) {
      // Render
      // "struct_value": {
      //   "fields": [
      Push("struct_value", Item::MESSAGE, true, false);
      Push("fields", Item::MAP, true, true);
    }
    return this;
  }

  const google::protobuf::Field* field = BeginNamed(name, false);
  if (field == NULL) return this;

  if (IsStruct(*field)) {
    // Start a struct object.
    // Render
    // "<name>": {
    //   "fields": {
    Push(name, Item::MESSAGE, false, false);
    Push("fields", Item::MAP, true, true);
    return this;
  }

  if (IsStructValue(*field)) {
    // We got a StartObject call with google.protobuf.Value field.  The only
    // object within that type is a struct type. So start a struct.
    // Render
    // "<name>": {
    //   "struct_value": {
    //     "fields": {
    Push(name, Item::MESSAGE, false, false);
    Push("struct_value", Item::MESSAGE, true, false);
    Push("fields", Item::MAP, true, true);
    return this;
  }

  if (IsMap(*field)) {
    // Begin a map. A map is triggered by a StartObject() call if the current
    // field has a map type.
    // A map type is always repeated, hence set is_list to true.
    // Render
    // "<name>": [
    Push(name, Item::MAP, false, true);
    return this;
  }

  // A regular message type. Pass it directly to ProtoWriter.
  // Render
  // "<name>": {
  Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
  return this;
}

ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
  if (invalid_depth() > 0) {
    DecrementInvalidDepth();
    return this;
  }

  if (current_ == NULL) return this;

  if (current_->IsAny()) {
    if (current_->any()->EndObject()) return this;
  }

  Pop();

  return this;
}

ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
  if (invalid_depth() > 0) {
    IncrementInvalidDepth();
    return this;
  }

  // Since we cannot have a top-level repeated item in protobuf, the only way
  // this is valid is if we start a special type google.protobuf.ListValue or
  // google.protobuf.Value.
  if (current_ == NULL) {
    if (!name.empty()) {
      InvalidName(name, "Root element should not be named.");
      IncrementInvalidDepth();
      return this;
    }

    // If master type is a special type that needs extra values to be written to
    // stream, we write those values.
    if (master_type_.name() == kStructValueType) {
      // We got a StartList with google.protobuf.Value master type. This means
      // we have to start the "list_value" within google.protobuf.Value.
      //
      // See
      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
      //
      // Render
      // "<name>": {
      //   "list_value": {
      //     "values": [  // Start this list.
      ProtoWriter::StartObject(name);
      current_.reset(new Item(this, Item::MESSAGE, false, false));
      Push("list_value", Item::MESSAGE, true, false);
      Push("values", Item::MESSAGE, true, true);
      return this;
    }

    if (master_type_.name() == kStructListValueType) {
      // We got a StartList with google.protobuf.ListValue master type. This
      // means we have to start the "values" within google.protobuf.ListValue.
      //
      // Render
      // "<name>": {
      //   "values": [  // Start this list.
      ProtoWriter::StartObject(name);
      current_.reset(new Item(this, Item::MESSAGE, false, false));
      Push("values", Item::MESSAGE, true, true);
      return this;
    }

    // Send the event to ProtoWriter so proper errors can be reported.
    //
    // Render a regular list:
    // "<name>": [
    ProtoWriter::StartList(name);
    current_.reset(new Item(this, Item::MESSAGE, false, true));
    return this;
  }

  if (current_->IsAny()) {
    current_->any()->StartList(name);
    return this;
  }

  // If the top of stack is a map, we are starting a list value within a map.
  // Since map does not allow repeated values, this can only happen when the map
  // value is of a special type that renders a list in JSON.  These can be one
  // of 3 cases:
  // i. We are rendering a list value within google.protobuf.Struct
  // ii. We are rendering a list value within google.protobuf.Value
  // iii. We are rendering a list value with type google.protobuf.ListValue.
  if (current_->IsMap()) {
    if (!ValidMapKey(name)) {
      IncrementInvalidDepth();
      return this;
    }

    // Start the repeated map entry object.
    // Render
    // { "key": "<name>", "value": {
    Push("", Item::MESSAGE, false, false);
    ProtoWriter::RenderDataPiece("key",
                                 DataPiece(name, use_strict_base64_decoding()));
    Push("value", Item::MESSAGE, true, false);

    // Make sure we are valid after pushing all above items.
    if (invalid_depth() > 0) return this;

    // case i and ii above. Start "list_value" field within g.p.Value
    if (element() != NULL && element()->parent_field() != NULL) {
      // Render
      // "list_value": {
      //   "values": [  // Start this list
      if (IsStructValue(*element()->parent_field())) {
        Push("list_value", Item::MESSAGE, true, false);
        Push("values", Item::MESSAGE, true, true);
        return this;
      }

      // Render
      // "values": [
      if (IsStructListValue(*element()->parent_field())) {
        // case iii above. Bind directly to g.p.ListValue
        Push("values", Item::MESSAGE, true, true);
        return this;
      }
    }

    // Report an error.
    InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
                               "') within a map."));
    return this;
  }

  // When name is empty and stack is not empty, we are rendering an item within
  // a list.
  if (name.empty()) {
    if (element() != NULL && element()->parent_field() != NULL) {
      if (IsStructValue(*element()->parent_field())) {
        // Since it is g.p.Value, we bind directly to the list_value.
        // Render
        // {  // g.p.Value item within the list
        //   "list_value": {
        //     "values": [
        Push("", Item::MESSAGE, false, false);
        Push("list_value", Item::MESSAGE, true, false);
        Push("values", Item::MESSAGE, true, true);
        return this;
      }

      if (IsStructListValue(*element()->parent_field())) {
        // Since it is g.p.ListValue, we bind to it directly.
        // Render
        // {  // g.p.ListValue item within the list
        //   "values": [
        Push("", Item::MESSAGE, false, false);
        Push("values", Item::MESSAGE, true, true);
        return this;
      }
    }

    // Pass the event to underlying ProtoWriter.
    Push(name, Item::MESSAGE, false, true);
    return this;
  }

  // name is not empty
  const google::protobuf::Field* field = Lookup(name);
  if (field == NULL) {
    IncrementInvalidDepth();
    return this;
  }

  if (IsStructValue(*field)) {
    // If g.p.Value is repeated, start that list. Otherwise, start the
    // "list_value" within it.
    if (IsRepeated(*field)) {
      // Render it just like a regular repeated field.
      // "<name>": [
      Push(name, Item::MESSAGE, false, true);
      return this;
    }

    // Start the "list_value" field.
    // Render
    // "<name>": {
    //   "list_value": {
    //     "values": [
    Push(name, Item::MESSAGE, false, false);
    Push("list_value", Item::MESSAGE, true, false);
    Push("values", Item::MESSAGE, true, true);
    return this;
  }

  if (IsStructListValue(*field)) {
    // If g.p.ListValue is repeated, start that list. Otherwise, start the
    // "values" within it.
    if (IsRepeated(*field)) {
      // Render it just like a regular repeated field.
      // "<name>": [
      Push(name, Item::MESSAGE, false, true);
      return this;
    }

    // Start the "values" field within g.p.ListValue.
    // Render
    // "<name>": {
    //   "values": [
    Push(name, Item::MESSAGE, false, false);
    Push("values", Item::MESSAGE, true, true);
    return this;
  }

  // If we are here, the field should be repeated. Report an error otherwise.
  if (!IsRepeated(*field)) {
    IncrementInvalidDepth();
    InvalidName(name, "Proto field is not repeating, cannot start list.");
    return this;
  }

  if (IsMap(*field)) {
    InvalidValue("Map",
                 StrCat("Cannot bind a list to map for field '", name, "'."));
    IncrementInvalidDepth();
    return this;
  }

  // Pass the event to ProtoWriter.
  // Render
  // "<name>": [
  Push(name, Item::MESSAGE, false, true);
  return this;
}

ProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() {
  if (invalid_depth() > 0) {
    DecrementInvalidDepth();
    return this;
  }

  if (current_ == NULL) return this;

  if (current_->IsAny()) {
    current_->any()->EndList();
    return this;
  }

  Pop();
  return this;
}

Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
                                                  const DataPiece& data) {
  string struct_field_name;
  switch (data.type()) {
    // Our JSON parser parses numbers as either int64, uint64, or double.
    case DataPiece::TYPE_INT64: {
      // If the option to treat integers as strings is set, then render them as
      // strings. Otherwise, fallback to rendering them as double.
      if (ow->options_.struct_integers_as_strings) {
        StatusOr<int64> int_value = data.ToInt64();
        if (int_value.ok()) {
          ow->ProtoWriter::RenderDataPiece(
              "string_value",
              DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
          return Status();
        }
      }
      struct_field_name = "number_value";
      break;
    }
    case DataPiece::TYPE_UINT64: {
      // If the option to treat integers as strings is set, then render them as
      // strings. Otherwise, fallback to rendering them as double.
      if (ow->options_.struct_integers_as_strings) {
        StatusOr<uint64> int_value = data.ToUint64();
        if (int_value.ok()) {
          ow->ProtoWriter::RenderDataPiece(
              "string_value",
              DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
          return Status();
        }
      }
      struct_field_name = "number_value";
      break;
    }
    case DataPiece::TYPE_DOUBLE: {
      if (ow->options_.struct_integers_as_strings) {
        StatusOr<double> double_value = data.ToDouble();
        if (double_value.ok()) {
          ow->ProtoWriter::RenderDataPiece(
              "string_value",
              DataPiece(SimpleDtoa(double_value.ValueOrDie()), true));
          return Status();
        }
      }
      struct_field_name = "number_value";
      break;
    }
    case DataPiece::TYPE_STRING: {
      struct_field_name = "string_value";
      break;
    }
    case DataPiece::TYPE_BOOL: {
      struct_field_name = "bool_value";
      break;
    }
    case DataPiece::TYPE_NULL: {
      struct_field_name = "null_value";
      break;
    }
    default: {
      return Status(INVALID_ARGUMENT,
                    "Invalid struct data type. Only number, string, boolean or "
                    "null values are supported.");
    }
  }
  ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
  return Status();
}

Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
                                                const DataPiece& data) {
  if (data.type() == DataPiece::TYPE_NULL) return Status();
  if (data.type() != DataPiece::TYPE_STRING) {
    return Status(INVALID_ARGUMENT,
                  StrCat("Invalid data type for timestamp, value is ",
                         data.ValueAsStringOrDefault("")));
  }

  StringPiece value(data.str());

  int64 seconds;
  int32 nanos;
  if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds,
                                               &nanos)) {
    return Status(INVALID_ARGUMENT, StrCat("Invalid time format: ", value));
  }

  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
  return Status();
}

static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
                                                StringPiece path) {
  ow->ProtoWriter::RenderDataPiece(
      "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true));
  return Status();
}

Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
                                                const DataPiece& data) {
  if (data.type() == DataPiece::TYPE_NULL) return Status();
  if (data.type() != DataPiece::TYPE_STRING) {
    return Status(INVALID_ARGUMENT,
                  StrCat("Invalid data type for field mask, value is ",
                         data.ValueAsStringOrDefault("")));
  }

// TODO(tsun): figure out how to do proto descriptor based snake case
// conversions as much as possible. Because ToSnakeCase sometimes returns the
// wrong value.
  google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
      ::google::protobuf::NewPermanentCallback(&RenderOneFieldPath, ow));
  return DecodeCompactFieldMaskPaths(data.str(), callback.get());
}

Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
                                               const DataPiece& data) {
  if (data.type() == DataPiece::TYPE_NULL) return Status();
  if (data.type() != DataPiece::TYPE_STRING) {
    return Status(INVALID_ARGUMENT,
                  StrCat("Invalid data type for duration, value is ",
                         data.ValueAsStringOrDefault("")));
  }

  StringPiece value(data.str());

  if (!value.ends_with("s")) {
    return Status(INVALID_ARGUMENT,
                  "Illegal duration format; duration must end with 's'");
  }
  value = value.substr(0, value.size() - 1);
  int sign = 1;
  if (value.starts_with("-")) {
    sign = -1;
    value = value.substr(1);
  }

  StringPiece s_secs, s_nanos;
  SplitSecondsAndNanos(value, &s_secs, &s_nanos);
  uint64 unsigned_seconds;
  if (!safe_strtou64(s_secs, &unsigned_seconds)) {
    return Status(INVALID_ARGUMENT,
                  "Invalid duration format, failed to parse seconds");
  }

  int32 nanos = 0;
  Status nanos_status = GetNanosFromStringPiece(
      s_nanos, "Invalid duration format, failed to parse nano seconds",
      "Duration value exceeds limits", &nanos);
  if (!nanos_status.ok()) {
    return nanos_status;
  }
  nanos = sign * nanos;

  int64 seconds = sign * unsigned_seconds;
  if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
      nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
    return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
  }

  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
  return Status();
}

Status ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
                                                  const DataPiece& data) {
  if (data.type() == DataPiece::TYPE_NULL) return Status();
  ow->ProtoWriter::RenderDataPiece("value", data);
  return Status();
}

ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
    StringPiece name, const DataPiece& data) {
  Status status;
  if (invalid_depth() > 0) return this;

  if (current_ == NULL) {
    const TypeRenderer* type_renderer =
        FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
    if (type_renderer == NULL) {
      InvalidName(name, "Root element must be a message.");
      return this;
    }
    // Render the special type.
    // "<name>": {
    //   ... Render special type ...
    // }
    ProtoWriter::StartObject(name);
    status = (*type_renderer)(this, data);
    if (!status.ok()) {
      InvalidValue(master_type_.name(),
                   StrCat("Field '", name, "', ", status.error_message()));
    }
    ProtoWriter::EndObject();
    return this;
  }

  if (current_->IsAny()) {
    current_->any()->RenderDataPiece(name, data);
    return this;
  }

  const google::protobuf::Field* field = NULL;
  if (current_->IsMap()) {
    if (!ValidMapKey(name)) return this;

    // Render an item in repeated map list.
    // { "key": "<name>", "value":
    Push("", Item::MESSAGE, false, false);
    ProtoWriter::RenderDataPiece("key",
                                 DataPiece(name, use_strict_base64_decoding()));
    field = Lookup("value");
    if (field == NULL) {
      Pop();
      GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
      return this;
    }

    const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
    if (type_renderer != NULL) {
      // Map's value type is a special type. Render it like a message:
      // "value": {
      //   ... Render special type ...
      // }
      Push("value", Item::MESSAGE, true, false);
      status = (*type_renderer)(this, data);
      if (!status.ok()) {
        InvalidValue(field->type_url(),
                     StrCat("Field '", name, "', ", status.error_message()));
      }
      Pop();
      return this;
    }

    // If we are rendering explicit null values and the backend proto field is
    // not of the google.protobuf.NullType type, we do nothing.
    if (data.type() == DataPiece::TYPE_NULL &&
        field->type_url() != kStructNullValueTypeUrl) {
      Pop();
      return this;
    }

    // Render the map value as a primitive type.
    ProtoWriter::RenderDataPiece("value", data);
    Pop();
    return this;
  }

  field = Lookup(name);
  if (field == NULL) return this;

  // Check if the field is of special type. Render it accordingly if so.
  const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
  if (type_renderer != NULL) {
    // Pass through null value only for google.protobuf.Value. For other
    // types we ignore null value just like for regular field types.
    if (data.type() != DataPiece::TYPE_NULL ||
        field->type_url() == kStructValueTypeUrl) {
      Push(name, Item::MESSAGE, false, false);
      status = (*type_renderer)(this, data);
      if (!status.ok()) {
        InvalidValue(field->type_url(),
                     StrCat("Field '", name, "', ", status.error_message()));
      }
      Pop();
    }
    return this;
  }

  // If we are rendering explicit null values and the backend proto field is
  // not of the google.protobuf.NullType type, we do nothing.
  if (data.type() == DataPiece::TYPE_NULL &&
      field->type_url() != kStructNullValueTypeUrl) {
    return this;
  }

  ProtoWriter::RenderDataPiece(name, data);
  return this;
}

// Map of functions that are responsible for rendering well known type
// represented by the key.
hash_map<string, ProtoStreamObjectWriter::TypeRenderer>*
    ProtoStreamObjectWriter::renderers_ = NULL;
GOOGLE_PROTOBUF_DECLARE_ONCE(writer_renderers_init_);

void ProtoStreamObjectWriter::InitRendererMap() {
  renderers_ = new hash_map<string, ProtoStreamObjectWriter::TypeRenderer>();
  (*renderers_)["type.googleapis.com/google.protobuf.Timestamp"] =
      &ProtoStreamObjectWriter::RenderTimestamp;
  (*renderers_)["type.googleapis.com/google.protobuf.Duration"] =
      &ProtoStreamObjectWriter::RenderDuration;
  (*renderers_)["type.googleapis.com/google.protobuf.FieldMask"] =
      &ProtoStreamObjectWriter::RenderFieldMask;
  (*renderers_)["type.googleapis.com/google.protobuf.Double"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.Float"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.Int64"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.UInt64"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.Int32"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.UInt32"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.Bool"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.String"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.Bytes"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.DoubleValue"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.FloatValue"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.Int64Value"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.UInt64Value"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.Int32Value"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.UInt32Value"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.BoolValue"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.StringValue"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.BytesValue"] =
      &ProtoStreamObjectWriter::RenderWrapperType;
  (*renderers_)["type.googleapis.com/google.protobuf.Value"] =
      &ProtoStreamObjectWriter::RenderStructValue;
  ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
}

void ProtoStreamObjectWriter::DeleteRendererMap() {
  delete ProtoStreamObjectWriter::renderers_;
  renderers_ = NULL;
}

ProtoStreamObjectWriter::TypeRenderer*
ProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) {
  ::google::protobuf::GoogleOnceInit(&writer_renderers_init_, &InitRendererMap);
  return FindOrNull(*renderers_, type_url);
}

bool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
  if (current_ == NULL) return true;

  if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
    listener()->InvalidName(
        location(), unnormalized_name,
        StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
    return false;
  }

  return true;
}

void ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type,
                                   bool is_placeholder, bool is_list) {
  is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name);

  // invalid_depth == 0 means it is a successful StartObject or StartList.
  if (invalid_depth() == 0)
    current_.reset(
        new Item(current_.release(), item_type, is_placeholder, is_list));
}

void ProtoStreamObjectWriter::Pop() {
  // Pop all placeholder items sending StartObject or StartList events to
  // ProtoWriter according to is_list value.
  while (current_ != NULL && current_->is_placeholder()) {
    PopOneElement();
  }
  if (current_ != NULL) {
    PopOneElement();
  }
}

void ProtoStreamObjectWriter::PopOneElement() {
  current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject();
  current_.reset(current_->pop<Item>());
}

bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
  if (field.type_url().empty() ||
      field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE ||
      field.cardinality() !=
          google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
    return false;
  }
  const google::protobuf::Type* field_type =
      typeinfo()->GetTypeByTypeUrl(field.type_url());

  return google::protobuf::util::converter::IsMap(field, *field_type);
}

bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
  return GetTypeWithoutUrl(field.type_url()) == kAnyType;
}

bool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) {
  return GetTypeWithoutUrl(field.type_url()) == kStructType;
}

bool ProtoStreamObjectWriter::IsStructValue(
    const google::protobuf::Field& field) {
  return GetTypeWithoutUrl(field.type_url()) == kStructValueType;
}

bool ProtoStreamObjectWriter::IsStructListValue(
    const google::protobuf::Field& field) {
  return GetTypeWithoutUrl(field.type_url()) == kStructListValueType;
}

}  // namespace converter
}  // namespace util
}  // namespace protobuf
}  // namespace google