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 <cstdint>
34 #include <unordered_map>
35 
36 #include <google/protobuf/util/internal/constants.h>
37 #include <google/protobuf/util/internal/utility.h>
38 #include <google/protobuf/stubs/map_util.h>
39 
40 namespace google {
41 namespace protobuf {
42 namespace util {
43 namespace converter {
44 
45 namespace {
46 // Helper function to convert string value to given data type by calling the
47 // passed converter function on the DataPiece created from "value" argument.
48 // If value is empty or if conversion fails, the default_value is returned.
49 template <typename T>
ConvertTo(StringPiece value,util::StatusOr<T> (DataPiece::* converter_fn)()const,T default_value)50 T ConvertTo(StringPiece value,
51             util::StatusOr<T> (DataPiece::*converter_fn)() const,
52             T default_value) {
53   if (value.empty()) return default_value;
54   util::StatusOr<T> result = (DataPiece(value, true).*converter_fn)();
55   return result.ok() ? result.value() : 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       ow_(ow) {}
71 
~DefaultValueObjectWriter()72 DefaultValueObjectWriter::~DefaultValueObjectWriter() {
73   if (own_typeinfo_) {
74     delete typeinfo_;
75   }
76 }
77 
RenderBool(StringPiece name,bool value)78 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBool(
79     StringPiece name, bool value) {
80   if (current_ == nullptr) {
81     ow_->RenderBool(name, value);
82   } else {
83     RenderDataPiece(name, DataPiece(value));
84   }
85   return this;
86 }
87 
RenderInt32(StringPiece name,int32_t value)88 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt32(
89     StringPiece name, int32_t value) {
90   if (current_ == nullptr) {
91     ow_->RenderInt32(name, value);
92   } else {
93     RenderDataPiece(name, DataPiece(value));
94   }
95   return this;
96 }
97 
RenderUint32(StringPiece name,uint32_t value)98 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint32(
99     StringPiece name, uint32_t value) {
100   if (current_ == nullptr) {
101     ow_->RenderUint32(name, value);
102   } else {
103     RenderDataPiece(name, DataPiece(value));
104   }
105   return this;
106 }
107 
RenderInt64(StringPiece name,int64_t value)108 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderInt64(
109     StringPiece name, int64_t value) {
110   if (current_ == nullptr) {
111     ow_->RenderInt64(name, value);
112   } else {
113     RenderDataPiece(name, DataPiece(value));
114   }
115   return this;
116 }
117 
RenderUint64(StringPiece name,uint64_t value)118 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderUint64(
119     StringPiece name, uint64_t value) {
120   if (current_ == nullptr) {
121     ow_->RenderUint64(name, value);
122   } else {
123     RenderDataPiece(name, DataPiece(value));
124   }
125   return this;
126 }
127 
RenderDouble(StringPiece name,double value)128 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderDouble(
129     StringPiece name, double value) {
130   if (current_ == nullptr) {
131     ow_->RenderDouble(name, value);
132   } else {
133     RenderDataPiece(name, DataPiece(value));
134   }
135   return this;
136 }
137 
RenderFloat(StringPiece name,float value)138 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderFloat(
139     StringPiece name, float value) {
140   if (current_ == nullptr) {
141     ow_->RenderBool(name, value);
142   } else {
143     RenderDataPiece(name, DataPiece(value));
144   }
145   return this;
146 }
147 
RenderString(StringPiece name,StringPiece value)148 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString(
149     StringPiece name, StringPiece value) {
150   if (current_ == nullptr) {
151     ow_->RenderString(name, value);
152   } else {
153     // Since StringPiece is essentially a pointer, takes a copy of "value" to
154     // avoid ownership issues.
155     string_values_.emplace_back(new std::string(value));
156     RenderDataPiece(name, DataPiece(*string_values_.back(), true));
157   }
158   return this;
159 }
160 
RenderBytes(StringPiece name,StringPiece value)161 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes(
162     StringPiece name, StringPiece value) {
163   if (current_ == nullptr) {
164     ow_->RenderBytes(name, value);
165   } else {
166     // Since StringPiece is essentially a pointer, takes a copy of "value" to
167     // avoid ownership issues.
168     string_values_.emplace_back(new std::string(value));
169     RenderDataPiece(name, DataPiece(*string_values_.back(), false, true));
170   }
171   return this;
172 }
173 
RenderNull(StringPiece name)174 DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull(
175     StringPiece name) {
176   if (current_ == nullptr) {
177     ow_->RenderNull(name);
178   } else {
179     RenderDataPiece(name, DataPiece::NullData());
180   }
181   return this;
182 }
183 
RegisterFieldScrubCallBack(FieldScrubCallBack field_scrub_callback)184 void DefaultValueObjectWriter::RegisterFieldScrubCallBack(
185     FieldScrubCallBack field_scrub_callback) {
186   field_scrub_callback_ = std::move(field_scrub_callback);
187 }
188 
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)189 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::CreateNewNode(
190     const std::string& name, const google::protobuf::Type* type, NodeKind kind,
191     const DataPiece& data, bool is_placeholder,
192     const std::vector<std::string>& path, bool suppress_empty_list,
193     bool preserve_proto_field_names, bool use_ints_for_enums,
194     FieldScrubCallBack field_scrub_callback) {
195   return new Node(name, type, kind, data, is_placeholder, path,
196                   suppress_empty_list, preserve_proto_field_names,
197                   use_ints_for_enums, std::move(field_scrub_callback));
198 }
199 
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)200 DefaultValueObjectWriter::Node::Node(
201     const std::string& name, const google::protobuf::Type* type, NodeKind kind,
202     const DataPiece& data, bool is_placeholder,
203     const std::vector<std::string>& path, bool suppress_empty_list,
204     bool preserve_proto_field_names, bool use_ints_for_enums,
205     FieldScrubCallBack field_scrub_callback)
206     : name_(name),
207       type_(type),
208       kind_(kind),
209       is_any_(false),
210       data_(data),
211       is_placeholder_(is_placeholder),
212       path_(path),
213       suppress_empty_list_(suppress_empty_list),
214       preserve_proto_field_names_(preserve_proto_field_names),
215       use_ints_for_enums_(use_ints_for_enums),
216       field_scrub_callback_(std::move(field_scrub_callback)) {}
217 
FindChild(StringPiece name)218 DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild(
219     StringPiece name) {
220   if (name.empty() || kind_ != OBJECT) {
221     return nullptr;
222   }
223   for (Node* child : children_) {
224     if (child->name() == name) {
225       return child;
226     }
227   }
228   return nullptr;
229 }
230 
WriteTo(ObjectWriter * ow)231 void DefaultValueObjectWriter::Node::WriteTo(ObjectWriter* ow) {
232   if (kind_ == PRIMITIVE) {
233     ObjectWriter::RenderDataPieceTo(data_, name_, ow);
234     return;
235   }
236 
237   // Render maps. Empty maps are rendered as "{}".
238   if (kind_ == MAP) {
239     ow->StartObject(name_);
240     WriteChildren(ow);
241     ow->EndObject();
242     return;
243   }
244 
245   // Write out lists. If we didn't have any list in response, write out empty
246   // list.
247   if (kind_ == LIST) {
248     // Suppress empty lists if requested.
249     if (suppress_empty_list_ && is_placeholder_) return;
250 
251     ow->StartList(name_);
252     WriteChildren(ow);
253     ow->EndList();
254     return;
255   }
256 
257   // If is_placeholder_ = true, we didn't see this node in the response, so
258   // skip output.
259   if (is_placeholder_) return;
260 
261   ow->StartObject(name_);
262   WriteChildren(ow);
263   ow->EndObject();
264 }
265 
WriteChildren(ObjectWriter * ow)266 void DefaultValueObjectWriter::Node::WriteChildren(ObjectWriter* ow) {
267   for (Node* child : children_) {
268     child->WriteTo(ow);
269   }
270 }
271 
GetMapValueType(const google::protobuf::Type & found_type,const TypeInfo * typeinfo)272 const google::protobuf::Type* DefaultValueObjectWriter::Node::GetMapValueType(
273     const google::protobuf::Type& found_type, const TypeInfo* typeinfo) {
274   // If this field is a map, we should use the type of its "Value" as
275   // the type of the child node.
276   for (int i = 0; i < found_type.fields_size(); ++i) {
277     const google::protobuf::Field& sub_field = found_type.fields(i);
278     if (sub_field.number() != 2) {
279       continue;
280     }
281     if (sub_field.kind() != google::protobuf::Field::TYPE_MESSAGE) {
282       // This map's value type is not a message type. We don't need to
283       // get the field_type in this case.
284       break;
285     }
286     util::StatusOr<const google::protobuf::Type*> sub_type =
287         typeinfo->ResolveTypeUrl(sub_field.type_url());
288     if (!sub_type.ok()) {
289       GOOGLE_LOG(WARNING) << "Cannot resolve type '" << sub_field.type_url() << "'.";
290     } else {
291       return sub_type.value();
292     }
293     break;
294   }
295   return nullptr;
296 }
297 
PopulateChildren(const TypeInfo * typeinfo)298 void DefaultValueObjectWriter::Node::PopulateChildren(
299     const TypeInfo* typeinfo) {
300   // Ignores well known types that don't require automatically populating their
301   // primitive children. For type "Any", we only populate its children when the
302   // "@type" field is set.
303   // TODO(tsun): remove "kStructValueType" from the list. It's being checked
304   //     now because of a bug in the tool-chain that causes the "oneof_index"
305   //     of kStructValueType to not be set correctly.
306   if (type_ == nullptr || type_->name() == kAnyType ||
307       type_->name() == kStructType || type_->name() == kTimestampType ||
308       type_->name() == kDurationType || type_->name() == kStructValueType) {
309     return;
310   }
311   std::vector<Node*> new_children;
312   std::unordered_map<std::string, int> orig_children_map;
313 
314   // Creates a map of child nodes to speed up lookup.
315   for (int i = 0; i < children_.size(); ++i) {
316     InsertIfNotPresent(&orig_children_map, children_[i]->name_, i);
317   }
318 
319   for (int i = 0; i < type_->fields_size(); ++i) {
320     const google::protobuf::Field& field = type_->fields(i);
321 
322     // This code is checking if the field to be added to the tree should be
323     // scrubbed or not by calling the field_scrub_callback_ callback function.
324     std::vector<std::string> path;
325     if (!path_.empty()) {
326       path.insert(path.begin(), path_.begin(), path_.end());
327     }
328     path.push_back(field.name());
329     if (field_scrub_callback_ && field_scrub_callback_(path, &field)) {
330       continue;
331     }
332 
333     std::unordered_map<std::string, int>::iterator found =
334         orig_children_map.find(field.name());
335     // If the child field has already been set, we just add it to the new list
336     // of children.
337     if (found != orig_children_map.end()) {
338       new_children.push_back(children_[found->second]);
339       children_[found->second] = nullptr;
340       continue;
341     }
342 
343     const google::protobuf::Type* field_type = nullptr;
344     bool is_map = false;
345     NodeKind kind = PRIMITIVE;
346 
347     if (field.kind() == google::protobuf::Field::TYPE_MESSAGE) {
348       kind = OBJECT;
349       util::StatusOr<const google::protobuf::Type*> found_result =
350           typeinfo->ResolveTypeUrl(field.type_url());
351       if (!found_result.ok()) {
352         // "field" is of an unknown type.
353         GOOGLE_LOG(WARNING) << "Cannot resolve type '" << field.type_url() << "'.";
354       } else {
355         const google::protobuf::Type* found_type = found_result.value();
356         is_map = IsMap(field, *found_type);
357 
358         if (!is_map) {
359           field_type = found_type;
360         } else {
361           // If this field is a map, we should use the type of its "Value" as
362           // the type of the child node.
363           field_type = GetMapValueType(*found_type, typeinfo);
364           kind = MAP;
365         }
366       }
367     }
368 
369     if (!is_map &&
370         field.cardinality() == google::protobuf::Field::CARDINALITY_REPEATED) {
371       kind = LIST;
372     }
373 
374     // If oneof_index() != 0, the child field is part of a "oneof", which means
375     // the child field is optional and we shouldn't populate its default
376     // primitive value.
377     if (field.oneof_index() != 0 && kind == PRIMITIVE) continue;
378 
379     // If the child field is of primitive type, sets its data to the default
380     // value of its type.
381     std::unique_ptr<Node> child(
382         new Node(preserve_proto_field_names_ ? field.name() : field.json_name(),
383                  field_type, kind,
384                  kind == PRIMITIVE ? CreateDefaultDataPieceForField(
385                                          field, typeinfo, use_ints_for_enums_)
386                                    : DataPiece::NullData(),
387                  true, path, suppress_empty_list_, preserve_proto_field_names_,
388                  use_ints_for_enums_, field_scrub_callback_));
389     new_children.push_back(child.release());
390   }
391   // Adds all leftover nodes in children_ to the beginning of new_child.
392   for (int i = 0; i < children_.size(); ++i) {
393     if (children_[i] == nullptr) {
394       continue;
395     }
396     new_children.insert(new_children.begin(), children_[i]);
397     children_[i] = nullptr;
398   }
399   children_.swap(new_children);
400 }
401 
MaybePopulateChildrenOfAny(Node * node)402 void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) {
403   // If this is an "Any" node with "@type" already given and no other children
404   // have been added, populates its children.
405   if (node != nullptr && node->is_any() && node->type() != nullptr &&
406       node->type()->name() != kAnyType && node->number_of_children() == 1) {
407     node->PopulateChildren(typeinfo_);
408   }
409 }
410 
FindEnumDefault(const google::protobuf::Field & field,const TypeInfo * typeinfo,bool use_ints_for_enums)411 DataPiece DefaultValueObjectWriter::FindEnumDefault(
412     const google::protobuf::Field& field, const TypeInfo* typeinfo,
413     bool use_ints_for_enums) {
414   const google::protobuf::Enum* enum_type =
415       typeinfo->GetEnumByTypeUrl(field.type_url());
416   if (!enum_type) {
417     GOOGLE_LOG(WARNING) << "Could not find enum with type '" << field.type_url()
418                  << "'";
419     return DataPiece::NullData();
420   }
421   if (!field.default_value().empty()) {
422     if (!use_ints_for_enums) {
423       return DataPiece(field.default_value(), true);
424     } else {
425       const std::string& enum_default_value_name = field.default_value();
426       for (int enum_index = 0; enum_index < enum_type->enumvalue_size();
427            ++enum_index) {
428         auto& enum_value = enum_type->enumvalue(enum_index);
429         if (enum_value.name() == enum_default_value_name)
430           return DataPiece(enum_value.number());
431       }
432       GOOGLE_LOG(WARNING) << "Could not find enum value '" << enum_default_value_name
433                    << "' with type '" << field.type_url() << "'";
434       return DataPiece::NullData();
435     }
436   }
437   // We treat the first value as the default if none is specified.
438   return enum_type->enumvalue_size() > 0
439              ? (use_ints_for_enums
440                     ? DataPiece(enum_type->enumvalue(0).number())
441                     : DataPiece(enum_type->enumvalue(0).name(), true))
442              : DataPiece::NullData();
443 }
444 
CreateDefaultDataPieceForField(const google::protobuf::Field & field,const TypeInfo * typeinfo,bool use_ints_for_enums)445 DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField(
446     const google::protobuf::Field& field, const TypeInfo* typeinfo,
447     bool use_ints_for_enums) {
448   switch (field.kind()) {
449     case google::protobuf::Field::TYPE_DOUBLE: {
450       return DataPiece(ConvertTo<double>(
451           field.default_value(), &DataPiece::ToDouble, static_cast<double>(0)));
452     }
453     case google::protobuf::Field::TYPE_FLOAT: {
454       return DataPiece(ConvertTo<float>(
455           field.default_value(), &DataPiece::ToFloat, static_cast<float>(0)));
456     }
457     case google::protobuf::Field::TYPE_INT64:
458     case google::protobuf::Field::TYPE_SINT64:
459     case google::protobuf::Field::TYPE_SFIXED64: {
460       return DataPiece(ConvertTo<int64_t>(
461           field.default_value(), &DataPiece::ToInt64, static_cast<int64_t>(0)));
462     }
463     case google::protobuf::Field::TYPE_UINT64:
464     case google::protobuf::Field::TYPE_FIXED64: {
465       return DataPiece(ConvertTo<uint64_t>(field.default_value(),
466                                            &DataPiece::ToUint64,
467                                            static_cast<uint64_t>(0)));
468     }
469     case google::protobuf::Field::TYPE_INT32:
470     case google::protobuf::Field::TYPE_SINT32:
471     case google::protobuf::Field::TYPE_SFIXED32: {
472       return DataPiece(ConvertTo<int32_t>(
473           field.default_value(), &DataPiece::ToInt32, static_cast<int32_t>(0)));
474     }
475     case google::protobuf::Field::TYPE_BOOL: {
476       return DataPiece(
477           ConvertTo<bool>(field.default_value(), &DataPiece::ToBool, false));
478     }
479     case google::protobuf::Field::TYPE_STRING: {
480       return DataPiece(field.default_value(), true);
481     }
482     case google::protobuf::Field::TYPE_BYTES: {
483       return DataPiece(field.default_value(), false, true);
484     }
485     case google::protobuf::Field::TYPE_UINT32:
486     case google::protobuf::Field::TYPE_FIXED32: {
487       return DataPiece(ConvertTo<uint32_t>(field.default_value(),
488                                            &DataPiece::ToUint32,
489                                            static_cast<uint32_t>(0)));
490     }
491     case google::protobuf::Field::TYPE_ENUM: {
492       return FindEnumDefault(field, typeinfo, use_ints_for_enums);
493     }
494     default: {
495       return DataPiece::NullData();
496     }
497   }
498 }
499 
StartObject(StringPiece name)500 DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject(
501     StringPiece name) {
502   if (current_ == nullptr) {
503     std::vector<std::string> path;
504     root_.reset(CreateNewNode(std::string(name), &type_, OBJECT,
505                               DataPiece::NullData(), false, path,
506                               suppress_empty_list_, preserve_proto_field_names_,
507                               use_ints_for_enums_, field_scrub_callback_));
508     root_->PopulateChildren(typeinfo_);
509     current_ = root_.get();
510     return this;
511   }
512   MaybePopulateChildrenOfAny(current_);
513   Node* child = current_->FindChild(name);
514   if (current_->kind() == LIST || current_->kind() == MAP || child == nullptr) {
515     // If current_ is a list or a map node, we should create a new child and use
516     // the type of current_ as the type of the new child.
517     std::unique_ptr<Node> node(
518         CreateNewNode(std::string(name),
519                       ((current_->kind() == LIST || current_->kind() == MAP)
520                            ? current_->type()
521                            : nullptr),
522                       OBJECT, DataPiece::NullData(), false,
523                       child == nullptr ? current_->path() : child->path(),
524                       suppress_empty_list_, preserve_proto_field_names_,
525                       use_ints_for_enums_, field_scrub_callback_));
526     child = node.get();
527     current_->AddChild(node.release());
528   }
529 
530   child->set_is_placeholder(false);
531   if (child->kind() == OBJECT && child->number_of_children() == 0) {
532     child->PopulateChildren(typeinfo_);
533   }
534 
535   stack_.push(current_);
536   current_ = child;
537   return this;
538 }
539 
EndObject()540 DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() {
541   if (stack_.empty()) {
542     // The root object ends here. Writes out the tree.
543     WriteRoot();
544     return this;
545   }
546   current_ = stack_.top();
547   stack_.pop();
548   return this;
549 }
550 
StartList(StringPiece name)551 DefaultValueObjectWriter* DefaultValueObjectWriter::StartList(
552     StringPiece name) {
553   if (current_ == nullptr) {
554     std::vector<std::string> path;
555     root_.reset(CreateNewNode(std::string(name), &type_, LIST,
556                               DataPiece::NullData(), false, path,
557                               suppress_empty_list_, preserve_proto_field_names_,
558                               use_ints_for_enums_, field_scrub_callback_));
559     current_ = root_.get();
560     return this;
561   }
562   MaybePopulateChildrenOfAny(current_);
563   Node* child = current_->FindChild(name);
564   if (child == nullptr || child->kind() != LIST) {
565     std::unique_ptr<Node> node(CreateNewNode(
566         std::string(name), nullptr, LIST, DataPiece::NullData(), false,
567         child == nullptr ? current_->path() : child->path(),
568         suppress_empty_list_, preserve_proto_field_names_, use_ints_for_enums_,
569         field_scrub_callback_));
570     child = node.get();
571     current_->AddChild(node.release());
572   }
573   child->set_is_placeholder(false);
574 
575   stack_.push(current_);
576   current_ = child;
577   return this;
578 }
579 
WriteRoot()580 void DefaultValueObjectWriter::WriteRoot() {
581   root_->WriteTo(ow_);
582   root_.reset(nullptr);
583   current_ = nullptr;
584 }
585 
EndList()586 DefaultValueObjectWriter* DefaultValueObjectWriter::EndList() {
587   if (stack_.empty()) {
588     WriteRoot();
589     return this;
590   }
591   current_ = stack_.top();
592   stack_.pop();
593   return this;
594 }
595 
RenderDataPiece(StringPiece name,const DataPiece & data)596 void DefaultValueObjectWriter::RenderDataPiece(StringPiece name,
597                                                const DataPiece& data) {
598   MaybePopulateChildrenOfAny(current_);
599   if (current_->type() != nullptr && current_->type()->name() == kAnyType &&
600       name == "@type") {
601     util::StatusOr<std::string> data_string = data.ToString();
602     if (data_string.ok()) {
603       const std::string& string_value = data_string.value();
604       // If the type of current_ is "Any" and its "@type" field is being set
605       // here, sets the type of current_ to be the type specified by the
606       // "@type".
607       util::StatusOr<const google::protobuf::Type*> found_type =
608           typeinfo_->ResolveTypeUrl(string_value);
609       if (!found_type.ok()) {
610         GOOGLE_LOG(WARNING) << "Failed to resolve type '" << string_value << "'.";
611       } else {
612         current_->set_type(found_type.value());
613       }
614       current_->set_is_any(true);
615       // If the "@type" field is placed after other fields, we should populate
616       // other children of primitive type now. Otherwise, we should wait until
617       // the first value field is rendered before we populate the children,
618       // because the "value" field of a Any message could be omitted.
619       if (current_->number_of_children() > 1 && current_->type() != nullptr) {
620         current_->PopulateChildren(typeinfo_);
621       }
622     }
623   }
624   Node* child = current_->FindChild(name);
625   if (child == nullptr || child->kind() != PRIMITIVE) {
626     // No children are found, creates a new child.
627     std::unique_ptr<Node> node(
628         CreateNewNode(std::string(name), nullptr, PRIMITIVE, data, false,
629                       child == nullptr ? current_->path() : child->path(),
630                       suppress_empty_list_, preserve_proto_field_names_,
631                       use_ints_for_enums_, field_scrub_callback_));
632     current_->AddChild(node.release());
633   } else {
634     child->set_data(data);
635     child->set_is_placeholder(false);
636   }
637 }
638 
639 }  // namespace converter
640 }  // namespace util
641 }  // namespace protobuf
642 }  // namespace google
643