1b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Protocol Buffers - Google's data interchange format
2b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Copyright 2008 Google Inc.  All rights reserved.
3b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// https://developers.google.com/protocol-buffers/
4b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
5b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Redistribution and use in source and binary forms, with or without
6b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// modification, are permitted provided that the following conditions are
7b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// met:
8b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
9b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions of source code must retain the above copyright
10b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// notice, this list of conditions and the following disclaimer.
11b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Redistributions in binary form must reproduce the above
12b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// copyright notice, this list of conditions and the following disclaimer
13b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// in the documentation and/or other materials provided with the
14b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// distribution.
15b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//     * Neither the name of Google Inc. nor the names of its
16b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// contributors may be used to endorse or promote products derived from
17b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// this software without specific prior written permission.
18b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer//
19b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
31b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/util/internal/protostream_objectwriter.h>
32b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
33b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <functional>
34b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <stack>
35b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
36b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/stubs/once.h>
37b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/stubs/time.h>
38b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/wire_format_lite.h>
39b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/util/internal/field_mask_utility.h>
40b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/util/internal/object_location_tracker.h>
41b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/util/internal/constants.h>
42b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/util/internal/utility.h>
43b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/stubs/strutil.h>
44b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/stubs/map_util.h>
45b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer#include <google/protobuf/stubs/statusor.h>
46b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
47b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
48b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace google {
49b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace protobuf {
50b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace util {
51b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace converter {
52b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
53b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerusing google::protobuf::internal::WireFormatLite;
54b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerusing util::error::INVALID_ARGUMENT;
55b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerusing util::Status;
56b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerusing util::StatusOr;
57b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
58b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
59b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::ProtoStreamObjectWriter(
60b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    TypeResolver* type_resolver, const google::protobuf::Type& type,
61b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    strings::ByteSink* output, ErrorListener* listener,
62b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const ProtoStreamObjectWriter::Options& options)
63b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    : ProtoWriter(type_resolver, type, output, listener),
64b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      master_type_(type),
65b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      current_(NULL),
66b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      options_(options) {}
67b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
68b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::ProtoStreamObjectWriter(
69b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const TypeInfo* typeinfo, const google::protobuf::Type& type,
70b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    strings::ByteSink* output, ErrorListener* listener)
71b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    : ProtoWriter(typeinfo, type, output, listener),
72b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      master_type_(type),
73b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      current_(NULL),
74b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      options_(ProtoStreamObjectWriter::Options::Defaults()) {}
75b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
76b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::~ProtoStreamObjectWriter() {
77b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_ == NULL) return;
78b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Cleanup explicitly in order to avoid destructor stack overflow when input
79b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // is deeply nested.
80b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Cast to BaseElement to avoid doing additional checks (like missing fields)
81b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // during pop().
82b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  google::protobuf::scoped_ptr<BaseElement> element(
83b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      static_cast<BaseElement*>(current_.get())->pop<BaseElement>());
84b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (element != NULL) {
85b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    element.reset(element->pop<BaseElement>());
86b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
87b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
88b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
89b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammernamespace {
90b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Utility method to split a string representation of Timestamp or Duration and
91b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// return the parts.
92b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid SplitSecondsAndNanos(StringPiece input, StringPiece* seconds,
93b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                          StringPiece* nanos) {
94b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  size_t idx = input.rfind('.');
95b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (idx != string::npos) {
96b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *seconds = input.substr(0, idx);
97b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *nanos = input.substr(idx + 1);
98b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else {
99b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *seconds = input;
100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *nanos = StringPiece();
101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerStatus GetNanosFromStringPiece(StringPiece s_nanos,
105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               const char* parse_failure_message,
106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               const char* exceeded_limit_message,
107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               int32* nanos) {
108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  *nanos = 0;
109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Count the number of leading 0s and consume them.
111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int num_leading_zeros = 0;
112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (s_nanos.Consume("0")) {
113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    num_leading_zeros++;
114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int32 i_nanos = 0;
116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // 's_nanos' contains fractional seconds -- i.e. 'nanos' is equal to
117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // "0." + s_nanos.ToString() seconds. An int32 is used for the
118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // conversion to 'nanos', rather than a double, so that there is no
119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // loss of precision.
120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!s_nanos.empty() && !safe_strto32(s_nanos.ToString(), &i_nanos)) {
121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT, parse_failure_message);
122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (i_nanos > kNanosPerSecond || i_nanos < 0) {
124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT, exceeded_limit_message);
125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // s_nanos should only have digits. No whitespace.
127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (s_nanos.find_first_not_of("0123456789") != StringPiece::npos) {
128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT, parse_failure_message);
129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (i_nanos > 0) {
132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // 'scale' is the number of digits to the right of the decimal
133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // point in "0." + s_nanos.ToString()
134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int32 scale = num_leading_zeros + s_nanos.size();
135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // 'conversion' converts i_nanos into nanoseconds.
136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // conversion = kNanosPerSecond / static_cast<int32>(std::pow(10, scale))
137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // For efficiency, we precompute the conversion factor.
138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    int32 conversion = 0;
139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    switch (scale) {
140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 1:
141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 100000000;
142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 2:
144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 10000000;
145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 3:
147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 1000000;
148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 4:
150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 100000;
151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 5:
153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 10000;
154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 6:
156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 1000;
157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 7:
159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 100;
160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 8:
162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 10;
163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      case 9:
165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        conversion = 1;
166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        break;
167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      default:
168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return Status(INVALID_ARGUMENT, exceeded_limit_message);
169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    *nanos = i_nanos * conversion;
171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return Status::OK;
174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace
177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent)
179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    : parent_(parent),
180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ow_(),
181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      invalid_(false),
182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      data_(),
183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      output_(&data_),
184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      depth_(0),
185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      is_well_known_type_(false),
186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      well_known_type_render_(NULL) {}
187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::AnyWriter::~AnyWriter() {}
189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) {
191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ++depth_;
192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // If an object writer is absent, that means we have not called StartAny()
193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // before reaching here. This is an invalid state. StartAny() gets called
194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // whenever we see an "@type" being rendered (see AnyWriter::RenderDataPiece).
195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (ow_ == NULL) {
196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Make sure we are not already in an invalid state. This avoids making
197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // multiple unnecessary InvalidValue calls.
198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!invalid_) {
199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      parent_->InvalidValue("Any",
200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            StrCat("Missing or invalid @type for any field in ",
201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                   parent_->master_type_.name()));
202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      invalid_ = true;
203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else if (is_well_known_type_ && depth_ == 1) {
205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // For well-known types, the only other field besides "@type" should be a
206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "value" field.
207b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (name != "value" && !invalid_) {
208b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      parent_->InvalidValue("Any",
209b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            "Expect a \"value\" field for well-known types.");
210b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      invalid_ = true;
211b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
212b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ow_->StartObject("");
213b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else {
214b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Forward the call to the child writer if:
215b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   1. the type is not a well-known type.
216b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   2. or, we are in a nested Any, Struct, or Value object.
217b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ow_->StartObject(name);
218b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
219b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
220b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
221b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerbool ProtoStreamObjectWriter::AnyWriter::EndObject() {
222b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  --depth_;
223b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // As long as depth_ >= 0, we know we haven't reached the end of Any.
224b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Propagate these EndObject() calls to the contained ow_. For regular
225b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // message types, we propagate the end of Any as well.
226b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (ow_ != NULL && (depth_ >= 0 || !is_well_known_type_)) {
227b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ow_->EndObject();
228b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
229b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // A negative depth_ implies that we have reached the end of Any
230b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // object. Now we write out its contents.
231b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (depth_ < 0) {
232b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    WriteAny();
233b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return false;
234b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
235b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return true;
236b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
237b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
238b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) {
239b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ++depth_;
240b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // We expect ow_ to be present as this call only makes sense inside an Any.
241b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (ow_ == NULL) {
242b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!invalid_) {
243b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      parent_->InvalidValue("Any",
244b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            StrCat("Missing or invalid @type for any field in ",
245b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                   parent_->master_type_.name()));
246b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      invalid_ = true;
247b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
248b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else if (is_well_known_type_ && depth_ == 1) {
249b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (name != "value" && !invalid_) {
250b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      parent_->InvalidValue("Any",
251b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            "Expect a \"value\" field for well-known types.");
252b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      invalid_ = true;
253b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
254b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ow_->StartList("");
255b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else {
256b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ow_->StartList(name);
257b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
258b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
259b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
260b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::AnyWriter::EndList() {
261b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  --depth_;
262b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (depth_ < 0) {
263b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    GOOGLE_LOG(DFATAL) << "Mismatched EndList found, should not be possible";
264b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    depth_ = 0;
265b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
266b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // We don't write an error on the close, only on the open
267b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (ow_ != NULL) {
268b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ow_->EndList();
269b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
270b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
271b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
272b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::AnyWriter::RenderDataPiece(
273b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    StringPiece name, const DataPiece& value) {
274b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Start an Any only at depth_ 0. Other RenderDataPiece calls with "@type"
275b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // should go to the contained ow_ as they indicate nested Anys.
276b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (depth_ == 0 && ow_ == NULL && name == "@type") {
277b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    StartAny(value);
278b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else if (ow_ == NULL) {
279b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!invalid_) {
280b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      parent_->InvalidValue("Any",
281b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            StrCat("Missing or invalid @type for any field in ",
282b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                   parent_->master_type_.name()));
283b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      invalid_ = true;
284b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
285b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else if (depth_ == 0 && is_well_known_type_) {
286b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (name != "value" && !invalid_) {
287b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      parent_->InvalidValue("Any",
288b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                            "Expect a \"value\" field for well-known types.");
289b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      invalid_ = true;
290b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
291b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (well_known_type_render_ == NULL) {
292b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Only Any and Struct don't have a special type render but both of
293b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // them expect a JSON object (i.e., a StartObject() call).
294b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (!invalid_) {
295b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        parent_->InvalidValue("Any", "Expect a JSON object.");
296b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        invalid_ = true;
297b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
298b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    } else {
299b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ow_->ProtoWriter::StartObject("");
300b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Status status = (*well_known_type_render_)(ow_.get(), value);
301b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (!status.ok()) ow_->InvalidValue("Any", status.error_message());
302b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ow_->ProtoWriter::EndObject();
303b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
304b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else {
305b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ow_->RenderDataPiece(name, value);
306b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
307b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
308b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
309b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) {
310b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Figure out the type url. This is a copy-paste from WriteString but we also
311b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // need the value, so we can't just call through to that.
312b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (value.type() == DataPiece::TYPE_STRING) {
313b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    type_url_ = value.str().ToString();
314b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  } else {
315b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    StatusOr<string> s = value.ToString();
316b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!s.ok()) {
317b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      parent_->InvalidValue("String", s.status().error_message());
318b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      invalid_ = true;
319b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return;
320b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
321b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    type_url_ = s.ValueOrDie();
322b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
323b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Resolve the type url, and report an error if we failed to resolve it.
324b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  StatusOr<const google::protobuf::Type*> resolved_type =
325b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      parent_->typeinfo()->ResolveTypeUrl(type_url_);
326b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!resolved_type.ok()) {
327b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    parent_->InvalidValue("Any", resolved_type.status().error_message());
328b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    invalid_ = true;
329b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return;
330b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
331b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // At this point, type is never null.
332b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const google::protobuf::Type* type = resolved_type.ValueOrDie();
333b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
334b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  well_known_type_render_ = FindTypeRenderer(type_url_);
335b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (well_known_type_render_ != NULL ||
336b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Explicitly list Any and Struct here because they don't have a
337b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // custom renderer.
338b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      type->name() == kAnyType || type->name() == kStructType) {
339b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    is_well_known_type_ = true;
340b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
341b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
342b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Create our object writer and initialize it with the first StartObject
343b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // call.
344b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_,
345b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                        parent_->listener()));
346b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
347b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Don't call StartObject() for well-known types yet. Depending on the
348b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // type of actual data, we may not need to call StartObject(). For
349b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // example:
350b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // {
351b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  //   "@type": "type.googleapis.com/google.protobuf.Value",
352b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  //   "value": [1, 2, 3],
353b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // }
354b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // With the above JSON representation, we will only call StartList() on the
355b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // contained ow_.
356b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!is_well_known_type_) {
357b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ow_->StartObject("");
358b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
359b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
360b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
361b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::AnyWriter::WriteAny() {
362b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (ow_ == NULL) {
363b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If we had no object writer, we never got any content, so just return
364b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // immediately, which is equivalent to writing an empty Any.
365b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return;
366b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
367b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Render the type_url and value fields directly to the stream.
368b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // type_url has tag 1 and value has tag 2.
369b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  WireFormatLite::WriteString(1, type_url_, parent_->stream());
370b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!data_.empty()) {
371b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    WireFormatLite::WriteBytes(2, data_, parent_->stream());
372b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
373b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
374b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
375b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter* enclosing,
376b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                    ItemType item_type, bool is_placeholder,
377b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                    bool is_list)
378b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    : BaseElement(NULL),
379b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ow_(enclosing),
380b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      any_(),
381b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      item_type_(item_type),
382b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      is_placeholder_(is_placeholder),
383b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      is_list_(is_list) {
384b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (item_type_ == ANY) {
385b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    any_.reset(new AnyWriter(ow_));
386b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
387b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
388b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
389b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
390b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                    ItemType item_type, bool is_placeholder,
391b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                    bool is_list)
392b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    : BaseElement(parent),
393b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ow_(this->parent()->ow_),
394b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      any_(),
395b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      item_type_(item_type),
396b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      is_placeholder_(is_placeholder),
397b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      is_list_(is_list) {
398b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (item_type == ANY) {
399b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    any_.reset(new AnyWriter(ow_));
400b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
401b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
402b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
403b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerbool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
404b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    StringPiece map_key) {
405b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return InsertIfNotPresent(&map_keys_, map_key.ToString());
406b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
407b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
408b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
409b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    StringPiece name) {
410b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (invalid_depth() > 0) {
411b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    IncrementInvalidDepth();
412b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
413b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
414b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
415b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Starting the root message. Create the root Item and return.
416b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // ANY message type does not need special handling, just set the ItemType
417b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // to ANY.
418b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_ == NULL) {
419b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoWriter::StartObject(name);
420b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    current_.reset(new Item(
421b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        this, master_type_.name() == kAnyType ? Item::ANY : Item::MESSAGE,
422b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        false, false));
423b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
424b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If master type is a special type that needs extra values to be written to
425b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // stream, we write those values.
426b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (master_type_.name() == kStructType) {
427b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Struct has a map<string, Value> field called "fields".
428b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
429b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "fields": [
430b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("fields", Item::MAP, true, true);
431b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
432b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
433b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
434b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (master_type_.name() == kStructValueType) {
435b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // We got a StartObject call with google.protobuf.Value field. The only
436b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // object within that type is a struct type. So start a struct.
437b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //
438b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // The struct field in Value type is named "struct_value"
439b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
440b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Also start the map field "fields" within the struct.
441b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "struct_value": {
442b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //   "fields": [
443b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("struct_value", Item::MESSAGE, true, false);
444b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("fields", Item::MAP, true, true);
445b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
446b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
447b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
448b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (master_type_.name() == kStructListValueType) {
449b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      InvalidValue(kStructListValueType,
450b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   "Cannot start root message with ListValue.");
451b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
452b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
453b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
454b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
455b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
456b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Send all ANY events to AnyWriter.
457b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_->IsAny()) {
458b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    current_->any()->StartObject(name);
459b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
460b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
461b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
462b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // If we are within a map, we render name as keys and send StartObject to the
463b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // value field.
464b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_->IsMap()) {
465b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!ValidMapKey(name)) {
466b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      IncrementInvalidDepth();
467b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
468b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
469b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
470b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Map is a repeated field of message type with a "key" and a "value" field.
471b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // https://developers.google.com/protocol-buffers/docs/proto3?hl=en#maps
472b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // message MapFieldEntry {
473b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   key_type key = 1;
474b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   value_type value = 2;
475b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // }
476b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //
477b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // repeated MapFieldEntry map_field = N;
478b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //
479b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // That means, we render the following element within a list (hence no
480b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // name):
481b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // { "key": "<name>", "value": {
482b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("", Item::MESSAGE, false, false);
483b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoWriter::RenderDataPiece("key",
484b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                 DataPiece(name, use_strict_base64_decoding()));
485b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("value", Item::MESSAGE, true, false);
486b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
487b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Make sure we are valid so far after starting map fields.
488b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (invalid_depth() > 0) return this;
489b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
490b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If top of stack is g.p.Struct type, start the struct the map field within
491b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // it.
492b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (element() != NULL && IsStruct(*element()->parent_field())) {
493b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Render "fields": [
494b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("fields", Item::MAP, true, true);
495b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
496b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
497b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
498b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If top of stack is g.p.Value type, start the Struct within it.
499b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (element() != NULL && IsStructValue(*element()->parent_field())) {
500b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Render
501b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "struct_value": {
502b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //   "fields": [
503b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("struct_value", Item::MESSAGE, true, false);
504b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("fields", Item::MAP, true, true);
505b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
506b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
507b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
508b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
509b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const google::protobuf::Field* field = BeginNamed(name, false);
510b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (field == NULL) return this;
511b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
512b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (IsStruct(*field)) {
513b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Start a struct object.
514b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render
515b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "<name>": {
516b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   "fields": {
517b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push(name, Item::MESSAGE, false, false);
518b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("fields", Item::MAP, true, true);
519b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
520b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
521b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
522b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (IsStructValue(*field)) {
523b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // We got a StartObject call with google.protobuf.Value field.  The only
524b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // object within that type is a struct type. So start a struct.
525b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render
526b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "<name>": {
527b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   "struct_value": {
528b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //     "fields": {
529b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push(name, Item::MESSAGE, false, false);
530b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("struct_value", Item::MESSAGE, true, false);
531b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("fields", Item::MAP, true, true);
532b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
533b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
534b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
535b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (IsMap(*field)) {
536b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Begin a map. A map is triggered by a StartObject() call if the current
537b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // field has a map type.
538b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // A map type is always repeated, hence set is_list to true.
539b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render
540b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "<name>": [
541b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push(name, Item::MAP, false, true);
542b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
543b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
544b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
545b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // A regular message type. Pass it directly to ProtoWriter.
546b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Render
547b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // "<name>": {
548b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Push(name, IsAny(*field) ? Item::ANY : Item::MESSAGE, false, false);
549b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return this;
550b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
551b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
552b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter* ProtoStreamObjectWriter::EndObject() {
553b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (invalid_depth() > 0) {
554b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    DecrementInvalidDepth();
555b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
556b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
557b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
558b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_ == NULL) return this;
559b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
560b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_->IsAny()) {
561b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (current_->any()->EndObject()) return this;
562b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
563b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
564b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Pop();
565b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
566b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return this;
567b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
568b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
569b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) {
570b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (invalid_depth() > 0) {
571b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    IncrementInvalidDepth();
572b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
573b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
574b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
575b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Since we cannot have a top-level repeated item in protobuf, the only way
576b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // this is valid is if we start a special type google.protobuf.ListValue or
577b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // google.protobuf.Value.
578b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_ == NULL) {
579b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!name.empty()) {
580b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      InvalidName(name, "Root element should not be named.");
581b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      IncrementInvalidDepth();
582b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
583b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
584b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
585b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If master type is a special type that needs extra values to be written to
586b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // stream, we write those values.
587b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (master_type_.name() == kStructValueType) {
588b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // We got a StartList with google.protobuf.Value master type. This means
589b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // we have to start the "list_value" within google.protobuf.Value.
590b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //
591b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // See
592b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // https://github.com/google/protobuf/blob/master/src/google/protobuf/struct.proto
593b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //
594b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Render
595b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "<name>": {
596b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //   "list_value": {
597b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //     "values": [  // Start this list.
598b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ProtoWriter::StartObject(name);
599b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      current_.reset(new Item(this, Item::MESSAGE, false, false));
600b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("list_value", Item::MESSAGE, true, false);
601b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("values", Item::MESSAGE, true, true);
602b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
603b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
604b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
605b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (master_type_.name() == kStructListValueType) {
606b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // We got a StartList with google.protobuf.ListValue master type. This
607b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // means we have to start the "values" within google.protobuf.ListValue.
608b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //
609b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Render
610b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "<name>": {
611b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //   "values": [  // Start this list.
612b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ProtoWriter::StartObject(name);
613b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      current_.reset(new Item(this, Item::MESSAGE, false, false));
614b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("values", Item::MESSAGE, true, true);
615b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
616b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
617b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
618b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Send the event to ProtoWriter so proper errors can be reported.
619b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //
620b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render a regular list:
621b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "<name>": [
622b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoWriter::StartList(name);
623b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    current_.reset(new Item(this, Item::MESSAGE, false, true));
624b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
625b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
626b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
627b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_->IsAny()) {
628b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    current_->any()->StartList(name);
629b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
630b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
631b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
632b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // If the top of stack is a map, we are starting a list value within a map.
633b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Since map does not allow repeated values, this can only happen when the map
634b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // value is of a special type that renders a list in JSON.  These can be one
635b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // of 3 cases:
636b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // i. We are rendering a list value within google.protobuf.Struct
637b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // ii. We are rendering a list value within google.protobuf.Value
638b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // iii. We are rendering a list value with type google.protobuf.ListValue.
639b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_->IsMap()) {
640b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!ValidMapKey(name)) {
641b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      IncrementInvalidDepth();
642b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
643b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
644b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
645b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Start the repeated map entry object.
646b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render
647b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // { "key": "<name>", "value": {
648b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("", Item::MESSAGE, false, false);
649b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoWriter::RenderDataPiece("key",
650b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                 DataPiece(name, use_strict_base64_decoding()));
651b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("value", Item::MESSAGE, true, false);
652b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
653b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Make sure we are valid after pushing all above items.
654b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (invalid_depth() > 0) return this;
655b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
656b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // case i and ii above. Start "list_value" field within g.p.Value
657b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (element() != NULL && element()->parent_field() != NULL) {
658b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Render
659b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "list_value": {
660b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //   "values": [  // Start this list
661b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (IsStructValue(*element()->parent_field())) {
662b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Push("list_value", Item::MESSAGE, true, false);
663b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Push("values", Item::MESSAGE, true, true);
664b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this;
665b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
666b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
667b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Render
668b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "values": [
669b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (IsStructListValue(*element()->parent_field())) {
670b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // case iii above. Bind directly to g.p.ListValue
671b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Push("values", Item::MESSAGE, true, true);
672b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this;
673b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
674b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
675b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
676b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Report an error.
677b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    InvalidValue("Map", StrCat("Cannot have repeated items ('", name,
678b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                               "') within a map."));
679b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
680b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
681b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
682b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // When name is empty and stack is not empty, we are rendering an item within
683b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // a list.
684b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (name.empty()) {
685b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (element() != NULL && element()->parent_field() != NULL) {
686b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (IsStructValue(*element()->parent_field())) {
687b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Since it is g.p.Value, we bind directly to the list_value.
688b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Render
689b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // {  // g.p.Value item within the list
690b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        //   "list_value": {
691b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        //     "values": [
692b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Push("", Item::MESSAGE, false, false);
693b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Push("list_value", Item::MESSAGE, true, false);
694b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Push("values", Item::MESSAGE, true, true);
695b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this;
696b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
697b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
698b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (IsStructListValue(*element()->parent_field())) {
699b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Since it is g.p.ListValue, we bind to it directly.
700b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // Render
701b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        // {  // g.p.ListValue item within the list
702b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        //   "values": [
703b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Push("", Item::MESSAGE, false, false);
704b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        Push("values", Item::MESSAGE, true, true);
705b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        return this;
706b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
707b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
708b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
709b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Pass the event to underlying ProtoWriter.
710b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push(name, Item::MESSAGE, false, true);
711b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
712b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
713b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
714b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // name is not empty
715b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const google::protobuf::Field* field = Lookup(name);
716b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (field == NULL) {
717b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    IncrementInvalidDepth();
718b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
719b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
720b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
721b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (IsStructValue(*field)) {
722b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If g.p.Value is repeated, start that list. Otherwise, start the
723b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "list_value" within it.
724b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (IsRepeated(*field)) {
725b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Render it just like a regular repeated field.
726b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "<name>": [
727b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push(name, Item::MESSAGE, false, true);
728b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
729b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
730b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
731b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Start the "list_value" field.
732b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render
733b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "<name>": {
734b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   "list_value": {
735b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //     "values": [
736b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push(name, Item::MESSAGE, false, false);
737b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("list_value", Item::MESSAGE, true, false);
738b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("values", Item::MESSAGE, true, true);
739b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
740b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
741b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
742b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (IsStructListValue(*field)) {
743b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If g.p.ListValue is repeated, start that list. Otherwise, start the
744b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "values" within it.
745b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (IsRepeated(*field)) {
746b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Render it just like a regular repeated field.
747b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "<name>": [
748b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push(name, Item::MESSAGE, false, true);
749b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
750b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
751b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
752b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Start the "values" field within g.p.ListValue.
753b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render
754b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "<name>": {
755b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   "values": [
756b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push(name, Item::MESSAGE, false, false);
757b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("values", Item::MESSAGE, true, true);
758b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
759b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
760b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
761b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // If we are here, the field should be repeated. Report an error otherwise.
762b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!IsRepeated(*field)) {
763b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    IncrementInvalidDepth();
764b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    InvalidName(name, "Proto field is not repeating, cannot start list.");
765b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
766b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
767b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
768b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (IsMap(*field)) {
769b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    InvalidValue("Map",
770b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                 StrCat("Cannot bind a list to map for field '", name, "'."));
771b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    IncrementInvalidDepth();
772b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
773b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
774b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
775b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Pass the event to ProtoWriter.
776b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Render
777b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // "<name>": [
778b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Push(name, Item::MESSAGE, false, true);
779b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return this;
780b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
781b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
782b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter* ProtoStreamObjectWriter::EndList() {
783b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (invalid_depth() > 0) {
784b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    DecrementInvalidDepth();
785b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
786b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
787b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
788b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_ == NULL) return this;
789b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
790b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_->IsAny()) {
791b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    current_->any()->EndList();
792b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
793b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
794b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
795b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Pop();
796b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return this;
797b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
798b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
799b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerStatus ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow,
800b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                  const DataPiece& data) {
801b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  string struct_field_name;
802b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  switch (data.type()) {
803b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Our JSON parser parses numbers as either int64, uint64, or double.
804b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case DataPiece::TYPE_INT64: {
805b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // If the option to treat integers as strings is set, then render them as
806b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // strings. Otherwise, fallback to rendering them as double.
807b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (ow->options_.struct_integers_as_strings) {
808b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        StatusOr<int64> int_value = data.ToInt64();
809b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (int_value.ok()) {
810b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          ow->ProtoWriter::RenderDataPiece(
811b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              "string_value",
812b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
813b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          return Status::OK;
814b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
815b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
816b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      struct_field_name = "number_value";
817b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
818b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
819b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case DataPiece::TYPE_UINT64: {
820b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // If the option to treat integers as strings is set, then render them as
821b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // strings. Otherwise, fallback to rendering them as double.
822b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (ow->options_.struct_integers_as_strings) {
823b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        StatusOr<uint64> int_value = data.ToUint64();
824b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        if (int_value.ok()) {
825b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          ow->ProtoWriter::RenderDataPiece(
826b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              "string_value",
827b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer              DataPiece(SimpleItoa(int_value.ValueOrDie()), true));
828b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          return Status::OK;
829b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        }
830b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
831b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      struct_field_name = "number_value";
832b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
833b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
834b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case DataPiece::TYPE_DOUBLE: {
835b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      struct_field_name = "number_value";
836b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
837b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
838b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case DataPiece::TYPE_STRING: {
839b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      struct_field_name = "string_value";
840b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
841b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
842b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case DataPiece::TYPE_BOOL: {
843b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      struct_field_name = "bool_value";
844b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
845b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
846b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    case DataPiece::TYPE_NULL: {
847b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      struct_field_name = "null_value";
848b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      break;
849b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
850b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    default: {
851b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return Status(INVALID_ARGUMENT,
852b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    "Invalid struct data type. Only number, string, boolean or "
853b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                    "null values are supported.");
854b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
855b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
856b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ow->ProtoWriter::RenderDataPiece(struct_field_name, data);
857b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return Status::OK;
858b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
859b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
860b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerStatus ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow,
861b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                const DataPiece& data) {
862b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (data.type() != DataPiece::TYPE_STRING) {
863b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT,
864b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                  StrCat("Invalid data type for timestamp, value is ",
865b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                         data.ValueAsStringOrDefault("")));
866b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
867b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
868b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  StringPiece value(data.str());
869b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
870b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int64 seconds;
871b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int32 nanos;
872b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!::google::protobuf::internal::ParseTime(value.ToString(), &seconds,
873b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                               &nanos)) {
874b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT, StrCat("Invalid time format: ", value));
875b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
876b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
877b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
878b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
879b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
880b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return Status::OK;
881b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
882b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
883b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerstatic inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow,
884b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                StringPiece path) {
885b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ow->ProtoWriter::RenderDataPiece(
886b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true));
887b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return Status::OK;
888b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
889b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
890b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerStatus ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow,
891b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                const DataPiece& data) {
892b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (data.type() != DataPiece::TYPE_STRING) {
893b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT,
894b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                  StrCat("Invalid data type for field mask, value is ",
895b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                         data.ValueAsStringOrDefault("")));
896b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
897b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
898b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// TODO(tsun): figure out how to do proto descriptor based snake case
899b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// conversions as much as possible. Because ToSnakeCase sometimes returns the
900b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// wrong value.
901b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  google::protobuf::scoped_ptr<ResultCallback1<util::Status, StringPiece> > callback(
902b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow));
903b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return DecodeCompactFieldMaskPaths(data.str(), callback.get());
904b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
905b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
906b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerStatus ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow,
907b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                               const DataPiece& data) {
908b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (data.type() != DataPiece::TYPE_STRING) {
909b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT,
910b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                  StrCat("Invalid data type for duration, value is ",
911b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                         data.ValueAsStringOrDefault("")));
912b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
913b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
914b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  StringPiece value(data.str());
915b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
916b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!value.ends_with("s")) {
917b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT,
918b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                  "Illegal duration format; duration must end with 's'");
919b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
920b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  value = value.substr(0, value.size() - 1);
921b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int sign = 1;
922b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (value.starts_with("-")) {
923b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    sign = -1;
924b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    value = value.substr(1);
925b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
926b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
927b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  StringPiece s_secs, s_nanos;
928b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  SplitSecondsAndNanos(value, &s_secs, &s_nanos);
929b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  uint64 unsigned_seconds;
930b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!safe_strtou64(s_secs, &unsigned_seconds)) {
931b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT,
932b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                  "Invalid duration format, failed to parse seconds");
933b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
934b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
935b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int32 nanos = 0;
936b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Status nanos_status = GetNanosFromStringPiece(
937b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      s_nanos, "Invalid duration format, failed to parse nano seconds",
938b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      "Duration value exceeds limits", &nanos);
939b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!nanos_status.ok()) {
940b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return nanos_status;
941b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
942b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  nanos = sign * nanos;
943b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
944b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  int64 seconds = sign * unsigned_seconds;
945b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds ||
946b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) {
947b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return Status(INVALID_ARGUMENT, "Duration value exceeds limits");
948b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
949b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
950b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ow->ProtoWriter::RenderDataPiece("seconds", DataPiece(seconds));
951b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ow->ProtoWriter::RenderDataPiece("nanos", DataPiece(nanos));
952b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return Status::OK;
953b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
954b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
955b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerStatus ProtoStreamObjectWriter::RenderWrapperType(ProtoStreamObjectWriter* ow,
956b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                                  const DataPiece& data) {
957b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ow->ProtoWriter::RenderDataPiece("value", data);
958b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return Status::OK;
959b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
960b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
961b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece(
962b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    StringPiece name, const DataPiece& data) {
963b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  Status status;
964b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (invalid_depth() > 0) return this;
965b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
966b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_ == NULL) {
967b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const TypeRenderer* type_renderer =
968b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        FindTypeRenderer(GetFullTypeWithUrl(master_type_.name()));
969b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (type_renderer == NULL) {
970b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      InvalidName(name, "Root element must be a message.");
971b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
972b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
973b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render the special type.
974b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // "<name>": {
975b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    //   ... Render special type ...
976b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // }
977b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoWriter::StartObject(name);
978b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    status = (*type_renderer)(this, data);
979b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!status.ok()) {
980b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      InvalidValue(master_type_.name(),
981b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   StrCat("Field '", name, "', ", status.error_message()));
982b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
983b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoWriter::EndObject();
984b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
985b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
986b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
987b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_->IsAny()) {
988b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    current_->any()->RenderDataPiece(name, data);
989b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
990b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
991b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
992b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const google::protobuf::Field* field = NULL;
993b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_->IsMap()) {
994b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!ValidMapKey(name)) return this;
995b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
996b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render an item in repeated map list.
997b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // { "key": "<name>", "value":
998b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push("", Item::MESSAGE, false, false);
999b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoWriter::RenderDataPiece("key",
1000b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                 DataPiece(name, use_strict_base64_decoding()));
1001b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    field = Lookup("value");
1002b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (field == NULL) {
1003b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
1004b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
1005b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1006b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1007b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
1008b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (type_renderer != NULL) {
1009b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // Map's value type is a special type. Render it like a message:
1010b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // "value": {
1011b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      //   ... Render special type ...
1012b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      // }
1013b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Push("value", Item::MESSAGE, true, false);
1014b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      status = (*type_renderer)(this, data);
1015b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      if (!status.ok()) {
1016b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        InvalidValue(field->type_url(),
1017b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                     StrCat("Field '", name, "', ", status.error_message()));
1018b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      }
1019b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Pop();
1020b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
1021b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1022b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1023b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // If we are rendering explicit null values and the backend proto field is
1024b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // not of the google.protobuf.NullType type, we do nothing.
1025b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (data.type() == DataPiece::TYPE_NULL &&
1026b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        field->type_url() != kStructNullValueTypeUrl) {
1027b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      Pop();
1028b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      return this;
1029b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1030b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1031b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    // Render the map value as a primitive type.
1032b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoWriter::RenderDataPiece("value", data);
1033b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Pop();
1034b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
1035b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1036b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1037b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  field = Lookup(name);
1038b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (field == NULL) return this;
1039b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1040b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Check if the field is of special type. Render it accordingly if so.
1041b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const TypeRenderer* type_renderer = FindTypeRenderer(field->type_url());
1042b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (type_renderer != NULL) {
1043b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Push(name, Item::MESSAGE, false, false);
1044b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    status = (*type_renderer)(this, data);
1045b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    if (!status.ok()) {
1046b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      InvalidValue(field->type_url(),
1047b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                   StrCat("Field '", name, "', ", status.error_message()));
1048b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    }
1049b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    Pop();
1050b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
1051b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1052b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1053b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // If we are rendering explicit null values and the backend proto field is
1054b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // not of the google.protobuf.NullType type, we do nothing.
1055b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (data.type() == DataPiece::TYPE_NULL &&
1056b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      field->type_url() != kStructNullValueTypeUrl) {
1057b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return this;
1058b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1059b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1060b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ProtoWriter::RenderDataPiece(name, data);
1061b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return this;
1062b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1063b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1064b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// Map of functions that are responsible for rendering well known type
1065b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer// represented by the key.
1066b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerhash_map<string, ProtoStreamObjectWriter::TypeRenderer>*
1067b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    ProtoStreamObjectWriter::renderers_ = NULL;
1068b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerGOOGLE_PROTOBUF_DECLARE_ONCE(writer_renderers_init_);
1069b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1070b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::InitRendererMap() {
1071b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  renderers_ = new hash_map<string, ProtoStreamObjectWriter::TypeRenderer>();
1072b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Timestamp"] =
1073b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderTimestamp;
1074b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Duration"] =
1075b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderDuration;
1076b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.FieldMask"] =
1077b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderFieldMask;
1078b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Double"] =
1079b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1080b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Float"] =
1081b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1082b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Int64"] =
1083b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1084b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.UInt64"] =
1085b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1086b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Int32"] =
1087b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1088b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.UInt32"] =
1089b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1090b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Bool"] =
1091b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1092b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.String"] =
1093b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1094b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Bytes"] =
1095b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1096b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.DoubleValue"] =
1097b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1098b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.FloatValue"] =
1099b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1100b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Int64Value"] =
1101b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1102b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.UInt64Value"] =
1103b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1104b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Int32Value"] =
1105b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1106b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.UInt32Value"] =
1107b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1108b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.BoolValue"] =
1109b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1110b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.StringValue"] =
1111b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1112b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.BytesValue"] =
1113b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderWrapperType;
1114b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  (*renderers_)["type.googleapis.com/google.protobuf.Value"] =
1115b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      &ProtoStreamObjectWriter::RenderStructValue;
1116b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ::google::protobuf::internal::OnShutdown(&DeleteRendererMap);
1117b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1118b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1119b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::DeleteRendererMap() {
1120b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  delete ProtoStreamObjectWriter::renderers_;
1121b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  renderers_ = NULL;
1122b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1123b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1124b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::TypeRenderer*
1125b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas BerghammerProtoStreamObjectWriter::FindTypeRenderer(const string& type_url) {
1126b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  ::google::protobuf::GoogleOnceInit(&writer_renderers_init_, &InitRendererMap);
1127b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return FindOrNull(*renderers_, type_url);
1128b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1129b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1130b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerbool ProtoStreamObjectWriter::ValidMapKey(StringPiece unnormalized_name) {
1131b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_ == NULL) return true;
1132b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1133b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (!current_->InsertMapKeyIfNotPresent(unnormalized_name)) {
1134b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    listener()->InvalidName(
1135b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        location(), unnormalized_name,
1136b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        StrCat("Repeated map key: '", unnormalized_name, "' is already set."));
1137b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return false;
1138b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1139b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1140b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return true;
1141b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1142b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1143b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::Push(StringPiece name, Item::ItemType item_type,
1144b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                   bool is_placeholder, bool is_list) {
1145b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  is_list ? ProtoWriter::StartList(name) : ProtoWriter::StartObject(name);
1146b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1147b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // invalid_depth == 0 means it is a successful StartObject or StartList.
1148b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (invalid_depth() == 0)
1149b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    current_.reset(
1150b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer        new Item(current_.release(), item_type, is_placeholder, is_list));
1151b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1152b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1153b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::Pop() {
1154b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // Pop all placeholder items sending StartObject or StartList events to
1155b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // ProtoWriter according to is_list value.
1156b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  while (current_ != NULL && current_->is_placeholder()) {
1157b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    PopOneElement();
1158b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1159b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (current_ != NULL) {
1160b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    PopOneElement();
1161b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1162b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1163b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1164b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammervoid ProtoStreamObjectWriter::PopOneElement() {
1165b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  current_->is_list() ? ProtoWriter::EndList() : ProtoWriter::EndObject();
1166b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  current_.reset(current_->pop<Item>());
1167b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1168b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1169b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerbool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
1170b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  if (field.type_url().empty() ||
1171b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE ||
1172b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      field.cardinality() !=
1173b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer          google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
1174b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    return false;
1175b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  }
1176b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  const google::protobuf::Type* field_type =
1177b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer      typeinfo()->GetTypeByTypeUrl(field.type_url());
1178b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1179b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  // TODO(xiaofeng): Unify option names.
1180b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return GetBoolOptionOrDefault(field_type->options(),
1181b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer                                "google.protobuf.MessageOptions.map_entry", false) ||
1182b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer         GetBoolOptionOrDefault(field_type->options(), "map_entry", false);
1183b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1184b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1185b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerbool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
1186b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return GetTypeWithoutUrl(field.type_url()) == kAnyType;
1187b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1188b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1189b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerbool ProtoStreamObjectWriter::IsStruct(const google::protobuf::Field& field) {
1190b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return GetTypeWithoutUrl(field.type_url()) == kStructType;
1191b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1192b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1193b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerbool ProtoStreamObjectWriter::IsStructValue(
1194b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const google::protobuf::Field& field) {
1195b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return GetTypeWithoutUrl(field.type_url()) == kStructValueType;
1196b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1197b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1198b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammerbool ProtoStreamObjectWriter::IsStructListValue(
1199b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer    const google::protobuf::Field& field) {
1200b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer  return GetTypeWithoutUrl(field.type_url()) == kStructListValueType;
1201b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}
1202b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer
1203b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace converter
1204b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace util
1205b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace protobuf
1206b0575e93e4c39dec69365b850088a1eb7f82c5b3Tamas Berghammer}  // namespace google
1207