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