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