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