• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include <google/protobuf/util/internal/default_value_objectwriter.h>
32 
33 #include <unordered_map>
34 
35 #include <google/protobuf/util/internal/constants.h>
36 #include <google/protobuf/util/internal/utility.h>
37 #include <google/protobuf/stubs/map_util.h>
38 
39 namespace google {
40 namespace protobuf {
41 namespace util {
42 using util::Status;
43 using util::StatusOr;
44 namespace converter {
45 
46 namespace {
47 // Helper function to convert string value to given data type by calling the
48 // passed converter function on the DataPiece created from "value" argument.
49 // If value is empty or if conversion fails, the default_value is returned.
50 template <typename T>
ConvertTo(StringPiece value,StatusOr<T> (DataPiece::* converter_fn)()const,T default_value)51 T ConvertTo(StringPiece value,
52             StatusOr<T> (DataPiece::*converter_fn)() const, T default_value) {
53   if (value.empty()) return default_value;
54   StatusOr<T> result = (DataPiece(value, true).*converter_fn)();
55   return result.ok() ? result.ValueOrDie() : default_value;
56 }
57 }  // namespace
58 
DefaultValueObjectWriter(TypeResolver * type_resolver,const google::protobuf::Type & type,ObjectWriter * ow)59 DefaultValueObjectWriter::DefaultValueObjectWriter(
60     TypeResolver* type_resolver, const google::protobuf::Type& type,
61     ObjectWriter* ow)
62     : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
63       own_typeinfo_(true),
64       type_(type),
65       current_(nullptr),
66       root_(nullptr),
67       suppress_empty_list_(false),
68       preserve_proto_field_names_(false),
69       use_ints_for_enums_(false),
70       field_scrub_callback_(nullptr),
71       ow_(ow) {}
72 
~DefaultValueObjectWriter()73 DefaultValueObjectWriter::~DefaultValueObjectWriter() {
74   if (own_typeinfo_) {
75     delete typeinfo_;
76   }
77 }
78 
RenderBool(StringPiece name,bool value)79 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(
80     StringPiece name, bool value) {
81   if (current_ == nullptr) {
82     ow_->RenderBool(name, value);
83   } else {
84     RenderDataPiece(name, DataPiece(value));
85   }
86   return this;
87 }
88 
RenderInt32(StringPiece name,int32 value)89 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
90     StringPiece name, int32 value) {
91   if (current_ == nullptr) {
92     ow_->RenderInt32(name, value);
93   } else {
94     RenderDataPiece(name, DataPiece(value));
95   }
96   return this;
97 }
98 
RenderUint32(StringPiece name,uint32 value)99 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
100     StringPiece name, uint32 value) {
101   if (current_ == nullptr) {
102     ow_->RenderUint32(name, value);
103   } else {
104     RenderDataPiece(name, DataPiece(value));
105   }
106   return this;
107 }
108 
RenderInt64(StringPiece name,int64 value)109 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
110     StringPiece name, int64 value) {
111   if (current_ == nullptr) {
112     ow_->RenderInt64(name, value);
113   } else {
114     RenderDataPiece(name, DataPiece(value));
115   }
116   return this;
117 }
118 
RenderUint64(StringPiece name,uint64 value)119 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
120     StringPiece name, uint64 value) {
121   if (current_ == nullptr) {
122     ow_->RenderUint64(name, value);
123   } else {
124     RenderDataPiece(name, DataPiece(value));
125   }
126   return this;
127 }
128 
RenderDouble(StringPiece name,double value)129 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
130     StringPiece name, double value) {
131   if (current_ == nullptr) {
132     ow_->RenderDouble(name, value);
133   } else {
134     RenderDataPiece(name, DataPiece(value));
135   }
136   return this;
137 }
138 
RenderFloat(StringPiece name,float value)139 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
140     StringPiece name, float value) {
141   if (current_ == nullptr) {
142     ow_->RenderBool(name, value);
143   } else {
144     RenderDataPiece(name, DataPiece(value));
145   }
146   return this;
147 }
148 
RenderString(StringPiece name,StringPiece value)149 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
150     StringPiece name, StringPiece value) {
151   if (current_ == nullptr) {
152     ow_->RenderString(name, value);
153   } else {
154     // Since StringPiece is essentially a pointer, takes a copy of "value" to
155     // avoid ownership issues.
156     string_values_.emplace_back(new std::string(value));
157     RenderDataPiece(name, DataPiece(*string_values_.back(), true));
158   }
159   return this;
160 }
161 
RenderBytes(StringPiece name,StringPiece value)162 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
163     StringPiece name, StringPiece value) {
164   if (current_ == nullptr) {
165     ow_->RenderBytes(name, value);
166   } else {
167     // Since StringPiece is essentially a pointer, takes a copy of "value" to
168     // avoid ownership issues.
169     string_values_.emplace_back(new std::string(value));
170     RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
171   }
172   return this;
173 }
174 
RenderNull(StringPiece name)175 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
176     StringPiece name) {
177   if (current_ == nullptr) {
178     ow_->RenderNull(name);
179   } else {
180     RenderDataPiece(name, DataPiece::NullData());
181   }
182   return this;
183 }
184 
RegisterFieldScrubCallBack(FieldScrubCallBackPtr field_scrub_callback)185 void DefaultValueObjectWriter::RegisterFieldScrubCallBack(
186     FieldScrubCallBackPtr field_scrub_callback) {
187   field_scrub_callback_.reset(field_scrub_callback.release());
188 }
189 
CreateNewNode(const std::string & name,const google::protobuf::Type * type,NodeKind kind,const DataPiece & data,bool is_placeholder,const std::vector<std::string> & path,bool suppress_empty_list,bool preserve_proto_field_names,bool use_ints_for_enums,FieldScrubCallBack * field_scrub_callback)190 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode(
191     const std::string& name, const google::protobuf::Type* type, NodeKind kind,
192     const DataPiece& data, bool is_placeholder,
193     const std::vector<std::string>& path, bool suppress_empty_list,
194     bool preserve_proto_field_names, bool use_ints_for_enums,
195     FieldScrubCallBack* field_scrub_callback) {
196   return new Node(name, type, kind, data, is_placeholder, path,
197                   suppress_empty_list, preserve_proto_field_names,
198                   use_ints_for_enums, field_scrub_callback);
199 }
200 
Node(const std::string & name,const google::protobuf::Type * type,NodeKind kind,const DataPiece & data,bool is_placeholder,const std::vector<std::string> & path,bool suppress_empty_list,bool preserve_proto_field_names,bool use_ints_for_enums,FieldScrubCallBack * field_scrub_callback)201 DefaultValueObjectWriter::Node::Node(
202     const std::string& name, const google::protobuf::Type* type, NodeKind kind,
203     const DataPiece& data, bool is_placeholder,
204     const std::vector<std::string>& path, bool suppress_empty_list,
205     bool preserve_proto_field_names, bool use_ints_for_enums,
206     FieldScrubCallBack* field_scrub_callback)
207     : name_(name),
208       type_(type),
209       kind_(kind),
210       is_any_(false),
211       data_(data),
212       is_placeholder_(is_placeholder),
213       path_(path),
214       suppress_empty_list_(suppress_empty_list),
215       preserve_proto_field_names_(preserve_proto_field_names),
216       use_ints_for_enums_(use_ints_for_enums),
217       field_scrub_callback_(field_scrub_callback) {}
218 
FindChild(StringPiece name)219 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
220     StringPiece name) {
221   if (name.empty() || kind_ != OBJECT) {
222     return nullptr;
223   }
224   for (int i = 0; i < children_.size(); ++i) {
225     Node* child = children_[i];
226     if (child->name() == name) {
227       return child;
228     }
229   }
230   return nullptr;
231 }
232 
WriteTo(ObjectWriter * ow)233 void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
234   if (kind_ == PRIMITIVE) {
235     ObjectWriter::RenderDataPieceTo(data_, name_, ow);
236     return;
237   }
238 
239   // Render maps. Empty maps are rendered as "{}".
240   if (kind_ == MAP) {
241     ow->StartObject(name_);
242     WriteChildren(ow);
243     ow->EndObject();
244     return;
245   }
246 
247   // Write out lists. If we didn't have any list in response, write out empty
248   // list.
249   if (kind_ == LIST) {
250     // Suppress empty lists if requested.
251     if (suppress_empty_list_ && is_placeholder_) return;
252 
253     ow->StartList(name_);
254     WriteChildren(ow);
255     ow->EndList();
256     return;
257   }
258 
259   // If is_placeholder_ = true, we didn't see this node in the response, so
260   // skip output.
261   if (is_placeholder_) return;
262 
263   ow->StartObject(name_);
264   WriteChildren(ow);
265   ow->EndObject();
266 }
267 
WriteChildren(ObjectWriter * ow)268 void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) {
269   for (int i = 0; i < children_.size(); ++i) {
270     Node* child = children_[i];
271     child->WriteTo(ow);
272   }
273 }
274 
GetMapValueType(const google::protobuf::Type & found_type,const TypeInfo * typeinfo)275 const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType(
276     const google::protobuf::Type& found_type, const TypeInfo* typeinfo) {
277   // If this field is a map, we should use the type of its "Value" as
278   // the type of the child node.
279   for (int i = 0; i < found_type.fields_size(); ++i) {
280     const google::protobuf::Field& sub_field = found_type.fields(i);
281     if (sub_field.number() != 2) {
282       continue;
283     }
284     if (sub_field.kind() != google::protobuf::Field_Kind_TYPE_MESSAGE) {
285       // This map's value type is not a message type. We don't need to
286       // get the field_type in this case.
287       break;
288     }
289     util::StatusOr<const google::protobuf::Type*> sub_type =
290         typeinfo->ResolveTypeUrl(sub_field.type_url());
291     if (!sub_type.ok()) {
292       GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'.";
293     } else {
294       return sub_type.ValueOrDie();
295     }
296     break;
297   }
298   return nullptr;
299 }
300 
PopulateChildren(const TypeInfo * typeinfo)301 void DefaultValueObjectWriter::Node::PopulateChildren(
302     const TypeInfo* typeinfo) {
303   // Ignores well known types that don't require automatically populating their
304   // primitive children. For type "Any", we only populate its children when the
305   // "@type" field is set.
306   // TODO(tsun): remove "kStructValueType" from the list. It's being checked
307   //     now because of a bug in the tool-chain that causes the "oneof_index"
308   //     of kStructValueType to not be set correctly.
309   if (type_ == nullptr || type_->name() == kAnyType ||
310       type_->name() == kStructType || type_->name() == kTimestampType ||
311       type_->name() == kDurationType || type_->name() == kStructValueType) {
312     return;
313   }
314   std::vector<Node*> new_children;
315   std::unordered_map<std::string, int> orig_children_map;
316 
317   // Creates a map of child nodes to speed up lookup.
318   for (int i = 0; i < children_.size(); ++i) {
319     InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
320   }
321 
322   for (int i = 0; i < type_->fields_size(); ++i) {
323     const google::protobuf::Field& field = type_->fields(i);
324 
325     // This code is checking if the field to be added to the tree should be
326     // scrubbed or not by calling the field_scrub_callback_ callback function.
327     std::vector<std::string> path;
328     if (!path_.empty()) {
329       path.insert(path.begin(), path_.begin(), path_.end());
330     }
331     path.push_back(field.name());
332     if (field_scrub_callback_ != nullptr &&
333         field_scrub_callback_->Run(path, &field)) {
334       continue;
335     }
336 
337     std::unordered_map<std::string, int>::iterator found =
338         orig_children_map.find(field.name());
339     // If the child field has already been set, we just add it to the new list
340     // of children.
341     if (found != orig_children_map.end()) {
342       new_children.push_back(children_[found->second]);
343       children_[found->second] = nullptr;
344       continue;
345     }
346 
347     const google::protobuf::Type* field_type = nullptr;
348     bool is_map = false;
349     NodeKind kind = PRIMITIVE;
350 
351     if (field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
352       kind = OBJECT;
353       util::StatusOr<const google::protobuf::Type*> found_result =
354           typeinfo->ResolveTypeUrl(field.type_url());
355       if (!found_result.ok()) {
356         // "field" is of an unknown type.
357         GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'.";
358       } else {
359         const google::protobuf::Type* found_type = found_result.ValueOrDie();
360         is_map = IsMap(field, *found_type);
361 
362         if (!is_map) {
363           field_type = found_type;
364         } else {
365           // If this field is a map, we should use the type of its "Value" as
366           // the type of the child node.
367           field_type = GetMapValueType(*found_type, typeinfo);
368           kind = MAP;
369         }
370       }
371     }
372 
373     if (!is_map &&
374         field.cardinality() ==
375             google::protobuf::Field_Cardinality_CARDINALITY_REPEATED) {
376       kind = LIST;
377     }
378 
379     // If oneof_index() != 0, the child field is part of a "oneof", which means
380     // the child field is optional and we shouldn't populate its default
381     // primitive value.
382     if (field.oneof_index() != 0 && kind == PRIMITIVE) continue;
383 
384     // If the child field is of primitive type, sets its data to the default
385     // value of its type.
386     std::unique_ptr<Node> child(
387         new Node(preserve_proto_field_names_ ? field.name() : field.json_name(),
388                  field_type, kind,
389                  kind == PRIMITIVE ? CreateDefaultDataPieceForField(
390                                          field, typeinfo, use_ints_for_enums_)
391                                    : DataPiece::NullData(),
392                  true, path, suppress_empty_list_, preserve_proto_field_names_,
393                  use_ints_for_enums_, field_scrub_callback_));
394     new_children.push_back(child.release());
395   }
396   // Adds all leftover nodes in children_ to the beginning of new_child.
397   for (int i = 0; i < children_.size(); ++i) {
398     if (children_[i] == nullptr) {
399       continue;
400     }
401     new_children.insert(new_children.begin(), children_[i]);
402     children_[i] = nullptr;
403   }
404   children_.swap(new_children);
405 }
406 
MaybePopulateChildrenOfAny(Node * node)407 void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
408   // If this is an "Any" node with "@type" already given and no other children
409   // have been added, populates its children.
410   if (node != nullptr && node->is_any() && node->type() != nullptr &&
411       node->type()->name() != kAnyType && node->number_of_children() == 1) {
412     node->PopulateChildren(typeinfo_);
413   }
414 }
415 
FindEnumDefault(const google::protobuf::Field & field,const TypeInfo * typeinfo,bool use_ints_for_enums)416 DataPiece DefaultValueObjectWriter::FindEnumDefault(
417     const google::protobuf::Field& field, const TypeInfo* typeinfo,
418     bool use_ints_for_enums) {
419   if (!field.default_value().empty())
420     return DataPiece(field.default_value(), true);
421 
422   const google::protobuf::Enum* enum_type =
423       typeinfo->GetEnumByTypeUrl(field.type_url());
424   if (!enum_type) {
425     GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
426                  << "'";
427     return DataPiece::NullData();
428   }
429   // We treat the first value as the default if none is specified.
430   return enum_type->enumvalue_size() > 0
431              ? (use_ints_for_enums
432                     ? DataPiece(enum_type->enumvalue(0).number())
433                     : DataPiece(enum_type->enumvalue(0).name(), true))
434              : DataPiece::NullData();
435 }
436 
CreateDefaultDataPieceForField(const google::protobuf::Field & field,const TypeInfo * typeinfo,bool use_ints_for_enums)437 DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
438     const google::protobuf::Field& field, const TypeInfo* typeinfo,
439     bool use_ints_for_enums) {
440   switch (field.kind()) {
441     case google::protobuf::Field_Kind_TYPE_DOUBLE: {
442       return DataPiece(ConvertTo<double>(
443           field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
444     }
445     case google::protobuf::Field_Kind_TYPE_FLOAT: {
446       return DataPiece(ConvertTo<float>(
447           field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
448     }
449     case google::protobuf::Field_Kind_TYPE_INT64:
450     case google::protobuf::Field_Kind_TYPE_SINT64:
451     case google::protobuf::Field_Kind_TYPE_SFIXED64: {
452       return DataPiece(ConvertTo<int64>(
453           field.default_value(), &DataPiece::ToInt64, static_cast<int64>(0)));
454     }
455     case google::protobuf::Field_Kind_TYPE_UINT64:
456     case google::protobuf::Field_Kind_TYPE_FIXED64: {
457       return DataPiece(ConvertTo<uint64>(
458           field.default_value(), &DataPiece::ToUint64, static_cast<uint64>(0)));
459     }
460     case google::protobuf::Field_Kind_TYPE_INT32:
461     case google::protobuf::Field_Kind_TYPE_SINT32:
462     case google::protobuf::Field_Kind_TYPE_SFIXED32: {
463       return DataPiece(ConvertTo<int32>(
464           field.default_value(), &DataPiece::ToInt32, static_cast<int32>(0)));
465     }
466     case google::protobuf::Field_Kind_TYPE_BOOL: {
467       return DataPiece(
468           ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
469     }
470     case google::protobuf::Field_Kind_TYPE_STRING: {
471       return DataPiece(field.default_value(), true);
472     }
473     case google::protobuf::Field_Kind_TYPE_BYTES: {
474       return DataPiece(field.default_value(), false, true);
475     }
476     case google::protobuf::Field_Kind_TYPE_UINT32:
477     case google::protobuf::Field_Kind_TYPE_FIXED32: {
478       return DataPiece(ConvertTo<uint32>(
479           field.default_value(), &DataPiece::ToUint32, static_cast<uint32>(0)));
480     }
481     case google::protobuf::Field_Kind_TYPE_ENUM: {
482       return FindEnumDefault(field, typeinfo, use_ints_for_enums);
483     }
484     default: {
485       return DataPiece::NullData();
486     }
487   }
488 }
489 
StartObject(StringPiece name)490 DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
491     StringPiece name) {
492   if (current_ == nullptr) {
493     std::vector<std::string> path;
494     root_.reset(CreateNewNode(
495         std::string(name), &type_, OBJECT, DataPiece::NullData(), false, path,
496         suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
497         field_scrub_callback_.get()));
498     root_->PopulateChildren(typeinfo_);
499     current_ = root_.get();
500     return this;
501   }
502   MaybePopulateChildrenOfAny(current_);
503   Node* child = current_->FindChild(name);
504   if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) {
505     // If current_ is a list or a map node, we should create a new child and use
506     // the type of current_ as the type of the new child.
507     std::unique_ptr<Node> node(
508         CreateNewNode(std::string(name),
509                       ((current_->kind() == LIST || current_->kind() == MAP)
510                            ? current_->type()
511                            : nullptr),
512                       OBJECT, DataPiece::NullData(), false,
513                       child == nullptr ? current_->path() : child->path(),
514                       suppress_empty_list_, preserve_proto_field_names_,
515                       use_ints_for_enums_, field_scrub_callback_.get()));
516     child = node.get();
517     current_->AddChild(node.release());
518   }
519 
520   child->set_is_placeholder(false);
521   if (child->kind() == OBJECT && child->number_of_children() == 0) {
522     child->PopulateChildren(typeinfo_);
523   }
524 
525   stack_.push(current_);
526   current_ = child;
527   return this;
528 }
529 
EndObject()530 DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() {
531   if (stack_.empty()) {
532     // The root object ends here. Writes out the tree.
533     WriteRoot();
534     return this;
535   }
536   current_ = stack_.top();
537   stack_.pop();
538   return this;
539 }
540 
StartList(StringPiece name)541 DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
542     StringPiece name) {
543   if (current_ == nullptr) {
544     std::vector<std::string> path;
545     root_.reset(CreateNewNode(
546         std::string(name), &type_, LIST, DataPiece::NullData(), false, path,
547         suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
548         field_scrub_callback_.get()));
549     current_ = root_.get();
550     return this;
551   }
552   MaybePopulateChildrenOfAny(current_);
553   Node* child = current_->FindChild(name);
554   if (child == nullptr || child->kind() != LIST) {
555     std::unique_ptr<Node> node(CreateNewNode(
556         std::string(name), nullptr, LIST, DataPiece::NullData(), false,
557         child == nullptr ? current_->path() : child->path(),
558         suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
559         field_scrub_callback_.get()));
560     child = node.get();
561     current_->AddChild(node.release());
562   }
563   child->set_is_placeholder(false);
564 
565   stack_.push(current_);
566   current_ = child;
567   return this;
568 }
569 
WriteRoot()570 void DefaultValueObjectWriter::WriteRoot() {
571   root_->WriteTo(ow_);
572   root_.reset(nullptr);
573   current_ = nullptr;
574 }
575 
EndList()576 DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() {
577   if (stack_.empty()) {
578     WriteRoot();
579     return this;
580   }
581   current_ = stack_.top();
582   stack_.pop();
583   return this;
584 }
585 
RenderDataPiece(StringPiece name,const DataPiece & data)586 void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
587                                                const DataPiece& data) {
588   MaybePopulateChildrenOfAny(current_);
589   if (current_->type() != nullptr && current_->type()->name() == kAnyType &&
590       name == "@type") {
591     util::StatusOr<std::string> data_string = data.ToString();
592     if (data_string.ok()) {
593       const std::string& string_value = data_string.ValueOrDie();
594       // If the type of current_ is "Any" and its "@type" field is being set
595       // here, sets the type of current_ to be the type specified by the
596       // "@type".
597       util::StatusOr<const google::protobuf::Type*> found_type =
598           typeinfo_->ResolveTypeUrl(string_value);
599       if (!found_type.ok()) {
600         GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.";
601       } else {
602         current_->set_type(found_type.ValueOrDie());
603       }
604       current_->set_is_any(true);
605       // If the "@type" field is placed after other fields, we should populate
606       // other children of primitive type now. Otherwise, we should wait until
607       // the first value field is rendered before we populate the children,
608       // because the "value" field of a Any message could be omitted.
609       if (current_->number_of_children() > 1 && current_->type() != nullptr) {
610         current_->PopulateChildren(typeinfo_);
611       }
612     }
613   }
614   Node* child = current_->FindChild(name);
615   if (child == nullptr || child->kind() != PRIMITIVE) {
616     // No children are found, creates a new child.
617     std::unique_ptr<Node> node(
618         CreateNewNode(std::string(name), nullptr, PRIMITIVE, data, false,
619                       child == nullptr ? current_->path() : child->path(),
620                       suppress_empty_list_, preserve_proto_field_names_,
621                       use_ints_for_enums_, field_scrub_callback_.get()));
622     current_->AddChild(node.release());
623   } else {
624     child->set_data(data);
625     child->set_is_placeholder(false);
626   }
627 }
628 
629 }  // namespace converter
630 }  // namespace util
631 }  // namespace protobuf
632 }  // namespace google
633