Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(990)

Side by Side Diff: third_party/protobuf/src/google/protobuf/util/internal/default_value_objectwriter.cc

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

Powered by Google App Engine
This is Rietveld 408576698