• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include <google/protobuf/util/internal/default_value_objectwriter.h>
32 
33 #include <google/protobuf/stubs/hash.h>
34 
35 #include <google/protobuf/util/internal/constants.h>
36 #include <google/protobuf/util/internal/utility.h>
37 #include <google/protobuf/stubs/map_util.h>
38 
39 namespace google {
40 namespace protobuf {
41 namespace util {
42 using util::Status;
43 using util::StatusOr;
44 namespace converter {
45 
46 namespace {
47 // Helper function to convert string value to given data type by calling the
48 // passed converter function on the DataPiece created from "value" argument.
49 // If value is empty or if conversion fails, the default_value is returned.
50 template <typename T>
ConvertTo(StringPiece value,StatusOr<T> (DataPiece::* converter_fn)()const,T default_value)51 T ConvertTo(StringPiece value, StatusOr<T> (DataPiece::*converter_fn)() const,
52             T default_value) {
53   if (value.empty()) return default_value;
54   StatusOr<T> result = (DataPiece(value, true).*converter_fn)();
55   return result.ok() ? result.ValueOrDie() : default_value;
56 }
57 }  // namespace
58 
DefaultValueObjectWriter(TypeResolver * type_resolver,const google::protobuf::Type & type,ObjectWriter * ow)59 DefaultValueObjectWriter::DefaultValueObjectWriter(
60     TypeResolver* type_resolver, const google::protobuf::Type& type,
61     ObjectWriter* ow)
62     : typeinfo_(TypeInfo::NewTypeInfo(type_resolver)),
63       own_typeinfo_(true),
64       type_(type),
65       current_(NULL),
66       root_(NULL),
67       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