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