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