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