1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/values.h"
6
7 #include <string.h>
8
9 #include <algorithm>
10 #include <cmath>
11 #include <ostream>
12 #include <utility>
13
14 #include "base/json/json_writer.h"
15 #include "base/logging.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/strings/string_util.h"
18 #include "base/strings/utf_string_conversions.h"
19
20 namespace base {
21
22 namespace {
23
24 const char* const kTypeNames[] = {"null", "boolean", "integer", "double",
25 "string", "binary", "dictionary", "list"};
26 static_assert(arraysize(kTypeNames) ==
27 static_cast<size_t>(Value::Type::LIST) + 1,
28 "kTypeNames Has Wrong Size");
29
30 std::unique_ptr<Value> CopyWithoutEmptyChildren(const Value& node);
31
32 // Make a deep copy of |node|, but don't include empty lists or dictionaries
33 // in the copy. It's possible for this function to return NULL and it
34 // expects |node| to always be non-NULL.
CopyListWithoutEmptyChildren(const ListValue & list)35 std::unique_ptr<ListValue> CopyListWithoutEmptyChildren(const ListValue& list) {
36 std::unique_ptr<ListValue> copy;
37 for (const auto& entry : list) {
38 std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(*entry);
39 if (child_copy) {
40 if (!copy)
41 copy.reset(new ListValue);
42 copy->Append(std::move(child_copy));
43 }
44 }
45 return copy;
46 }
47
CopyDictionaryWithoutEmptyChildren(const DictionaryValue & dict)48 std::unique_ptr<DictionaryValue> CopyDictionaryWithoutEmptyChildren(
49 const DictionaryValue& dict) {
50 std::unique_ptr<DictionaryValue> copy;
51 for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
52 std::unique_ptr<Value> child_copy = CopyWithoutEmptyChildren(it.value());
53 if (child_copy) {
54 if (!copy)
55 copy.reset(new DictionaryValue);
56 copy->SetWithoutPathExpansion(it.key(), std::move(child_copy));
57 }
58 }
59 return copy;
60 }
61
CopyWithoutEmptyChildren(const Value & node)62 std::unique_ptr<Value> CopyWithoutEmptyChildren(const Value& node) {
63 switch (node.GetType()) {
64 case Value::Type::LIST:
65 return CopyListWithoutEmptyChildren(static_cast<const ListValue&>(node));
66
67 case Value::Type::DICTIONARY:
68 return CopyDictionaryWithoutEmptyChildren(
69 static_cast<const DictionaryValue&>(node));
70
71 default:
72 return MakeUnique<Value>(node);
73 }
74 }
75
76 } // namespace
77
78 // static
CreateNullValue()79 std::unique_ptr<Value> Value::CreateNullValue() {
80 return WrapUnique(new Value(Type::NONE));
81 }
82
83 // static
CreateWithCopiedBuffer(const char * buffer,size_t size)84 std::unique_ptr<BinaryValue> BinaryValue::CreateWithCopiedBuffer(
85 const char* buffer,
86 size_t size) {
87 return MakeUnique<BinaryValue>(std::vector<char>(buffer, buffer + size));
88 }
89
Value(const Value & that)90 Value::Value(const Value& that) {
91 InternalCopyConstructFrom(that);
92 }
93
Value(Value && that)94 Value::Value(Value&& that) noexcept {
95 InternalMoveConstructFrom(std::move(that));
96 }
97
Value()98 Value::Value() noexcept : type_(Type::NONE) {}
99
Value(Type type)100 Value::Value(Type type) : type_(type) {
101 // Initialize with the default value.
102 switch (type_) {
103 case Type::NONE:
104 return;
105
106 case Type::BOOLEAN:
107 bool_value_ = false;
108 return;
109 case Type::INTEGER:
110 int_value_ = 0;
111 return;
112 case Type::DOUBLE:
113 double_value_ = 0.0;
114 return;
115 case Type::STRING:
116 string_value_.Init();
117 return;
118 case Type::BINARY:
119 binary_value_.Init();
120 return;
121 case Type::DICTIONARY:
122 dict_ptr_.Init(MakeUnique<DictStorage>());
123 return;
124 case Type::LIST:
125 list_.Init();
126 return;
127 }
128 }
129
Value(bool in_bool)130 Value::Value(bool in_bool) : type_(Type::BOOLEAN), bool_value_(in_bool) {}
131
Value(int in_int)132 Value::Value(int in_int) : type_(Type::INTEGER), int_value_(in_int) {}
133
Value(double in_double)134 Value::Value(double in_double) : type_(Type::DOUBLE), double_value_(in_double) {
135 if (!std::isfinite(double_value_)) {
136 NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
137 << "values cannot be represented in JSON";
138 double_value_ = 0.0;
139 }
140 }
141
Value(const char * in_string)142 Value::Value(const char* in_string) : type_(Type::STRING) {
143 string_value_.Init(in_string);
144 DCHECK(IsStringUTF8(*string_value_));
145 }
146
Value(const std::string & in_string)147 Value::Value(const std::string& in_string) : type_(Type::STRING) {
148 string_value_.Init(in_string);
149 DCHECK(IsStringUTF8(*string_value_));
150 }
151
Value(std::string && in_string)152 Value::Value(std::string&& in_string) noexcept : type_(Type::STRING) {
153 string_value_.Init(std::move(in_string));
154 DCHECK(IsStringUTF8(*string_value_));
155 }
156
Value(const char16 * in_string)157 Value::Value(const char16* in_string) : type_(Type::STRING) {
158 string_value_.Init(UTF16ToUTF8(in_string));
159 }
160
Value(const string16 & in_string)161 Value::Value(const string16& in_string) : type_(Type::STRING) {
162 string_value_.Init(UTF16ToUTF8(in_string));
163 }
164
Value(StringPiece in_string)165 Value::Value(StringPiece in_string) : Value(in_string.as_string()) {}
166
Value(const std::vector<char> & in_blob)167 Value::Value(const std::vector<char>& in_blob) : type_(Type::BINARY) {
168 binary_value_.Init(in_blob);
169 }
170
Value(std::vector<char> && in_blob)171 Value::Value(std::vector<char>&& in_blob) noexcept : type_(Type::BINARY) {
172 binary_value_.Init(std::move(in_blob));
173 }
174
operator =(const Value & that)175 Value& Value::operator=(const Value& that) {
176 if (type_ == that.type_) {
177 InternalCopyAssignFromSameType(that);
178 } else {
179 // This is not a self assignment because the type_ doesn't match.
180 InternalCleanup();
181 InternalCopyConstructFrom(that);
182 }
183
184 return *this;
185 }
186
operator =(Value && that)187 Value& Value::operator=(Value&& that) noexcept {
188 DCHECK(this != &that) << "attempt to self move assign.";
189 InternalCleanup();
190 InternalMoveConstructFrom(std::move(that));
191
192 return *this;
193 }
194
~Value()195 Value::~Value() {
196 InternalCleanup();
197 }
198
199 // static
GetTypeName(Value::Type type)200 const char* Value::GetTypeName(Value::Type type) {
201 DCHECK_GE(static_cast<int>(type), 0);
202 DCHECK_LT(static_cast<size_t>(type), arraysize(kTypeNames));
203 return kTypeNames[static_cast<size_t>(type)];
204 }
205
GetBool() const206 bool Value::GetBool() const {
207 CHECK(is_bool());
208 return bool_value_;
209 }
210
GetInt() const211 int Value::GetInt() const {
212 CHECK(is_int());
213 return int_value_;
214 }
215
GetDouble() const216 double Value::GetDouble() const {
217 if (is_double())
218 return double_value_;
219 if (is_int())
220 return int_value_;
221 CHECK(false);
222 return 0.0;
223 }
224
GetString() const225 const std::string& Value::GetString() const {
226 CHECK(is_string());
227 return *string_value_;
228 }
229
GetBlob() const230 const std::vector<char>& Value::GetBlob() const {
231 CHECK(is_blob());
232 return *binary_value_;
233 }
234
GetSize() const235 size_t Value::GetSize() const {
236 return GetBlob().size();
237 }
238
GetBuffer() const239 const char* Value::GetBuffer() const {
240 return GetBlob().data();
241 }
242
GetAsBoolean(bool * out_value) const243 bool Value::GetAsBoolean(bool* out_value) const {
244 if (out_value && is_bool()) {
245 *out_value = bool_value_;
246 return true;
247 }
248 return is_bool();
249 }
250
GetAsInteger(int * out_value) const251 bool Value::GetAsInteger(int* out_value) const {
252 if (out_value && is_int()) {
253 *out_value = int_value_;
254 return true;
255 }
256 return is_int();
257 }
258
GetAsDouble(double * out_value) const259 bool Value::GetAsDouble(double* out_value) const {
260 if (out_value && is_double()) {
261 *out_value = double_value_;
262 return true;
263 } else if (out_value && is_int()) {
264 // Allow promotion from int to double.
265 *out_value = int_value_;
266 return true;
267 }
268 return is_double() || is_int();
269 }
270
GetAsString(std::string * out_value) const271 bool Value::GetAsString(std::string* out_value) const {
272 if (out_value && is_string()) {
273 *out_value = *string_value_;
274 return true;
275 }
276 return is_string();
277 }
278
GetAsString(string16 * out_value) const279 bool Value::GetAsString(string16* out_value) const {
280 if (out_value && is_string()) {
281 *out_value = UTF8ToUTF16(*string_value_);
282 return true;
283 }
284 return is_string();
285 }
286
GetAsString(const Value ** out_value) const287 bool Value::GetAsString(const Value** out_value) const {
288 if (out_value && is_string()) {
289 *out_value = static_cast<const Value*>(this);
290 return true;
291 }
292 return is_string();
293 }
294
GetAsString(StringPiece * out_value) const295 bool Value::GetAsString(StringPiece* out_value) const {
296 if (out_value && is_string()) {
297 *out_value = *string_value_;
298 return true;
299 }
300 return is_string();
301 }
302
GetAsBinary(const BinaryValue ** out_value) const303 bool Value::GetAsBinary(const BinaryValue** out_value) const {
304 if (out_value && is_blob()) {
305 *out_value = this;
306 return true;
307 }
308 return is_blob();
309 }
310
GetAsList(ListValue ** out_value)311 bool Value::GetAsList(ListValue** out_value) {
312 if (out_value && is_list()) {
313 *out_value = static_cast<ListValue*>(this);
314 return true;
315 }
316 return is_list();
317 }
318
GetAsList(const ListValue ** out_value) const319 bool Value::GetAsList(const ListValue** out_value) const {
320 if (out_value && is_list()) {
321 *out_value = static_cast<const ListValue*>(this);
322 return true;
323 }
324 return is_list();
325 }
326
GetAsDictionary(DictionaryValue ** out_value)327 bool Value::GetAsDictionary(DictionaryValue** out_value) {
328 if (out_value && is_dict()) {
329 *out_value = static_cast<DictionaryValue*>(this);
330 return true;
331 }
332 return is_dict();
333 }
334
GetAsDictionary(const DictionaryValue ** out_value) const335 bool Value::GetAsDictionary(const DictionaryValue** out_value) const {
336 if (out_value && is_dict()) {
337 *out_value = static_cast<const DictionaryValue*>(this);
338 return true;
339 }
340 return is_dict();
341 }
342
DeepCopy() const343 Value* Value::DeepCopy() const {
344 return new Value(*this);
345 }
346
CreateDeepCopy() const347 std::unique_ptr<Value> Value::CreateDeepCopy() const {
348 return MakeUnique<Value>(*this);
349 }
350
operator ==(const Value & lhs,const Value & rhs)351 bool operator==(const Value& lhs, const Value& rhs) {
352 if (lhs.type_ != rhs.type_)
353 return false;
354
355 switch (lhs.type_) {
356 case Value::Type::NONE:
357 return true;
358 case Value::Type::BOOLEAN:
359 return lhs.bool_value_ == rhs.bool_value_;
360 case Value::Type::INTEGER:
361 return lhs.int_value_ == rhs.int_value_;
362 case Value::Type::DOUBLE:
363 return lhs.double_value_ == rhs.double_value_;
364 case Value::Type::STRING:
365 return *lhs.string_value_ == *rhs.string_value_;
366 case Value::Type::BINARY:
367 return *lhs.binary_value_ == *rhs.binary_value_;
368 // TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue
369 // are completely inlined.
370 case Value::Type::DICTIONARY:
371 if ((*lhs.dict_ptr_)->size() != (*rhs.dict_ptr_)->size())
372 return false;
373 return std::equal(std::begin(**lhs.dict_ptr_), std::end(**lhs.dict_ptr_),
374 std::begin(**rhs.dict_ptr_),
375 [](const Value::DictStorage::value_type& u,
376 const Value::DictStorage::value_type& v) {
377 return std::tie(u.first, *u.second) ==
378 std::tie(v.first, *v.second);
379 });
380 case Value::Type::LIST:
381 if (lhs.list_->size() != rhs.list_->size())
382 return false;
383 return std::equal(
384 std::begin(*lhs.list_), std::end(*lhs.list_), std::begin(*rhs.list_),
385 [](const Value::ListStorage::value_type& u,
386 const Value::ListStorage::value_type& v) { return *u == *v; });
387 }
388
389 NOTREACHED();
390 return false;
391 }
392
operator !=(const Value & lhs,const Value & rhs)393 bool operator!=(const Value& lhs, const Value& rhs) {
394 return !(lhs == rhs);
395 }
396
operator <(const Value & lhs,const Value & rhs)397 bool operator<(const Value& lhs, const Value& rhs) {
398 if (lhs.type_ != rhs.type_)
399 return lhs.type_ < rhs.type_;
400
401 switch (lhs.type_) {
402 case Value::Type::NONE:
403 return false;
404 case Value::Type::BOOLEAN:
405 return lhs.bool_value_ < rhs.bool_value_;
406 case Value::Type::INTEGER:
407 return lhs.int_value_ < rhs.int_value_;
408 case Value::Type::DOUBLE:
409 return lhs.double_value_ < rhs.double_value_;
410 case Value::Type::STRING:
411 return *lhs.string_value_ < *rhs.string_value_;
412 case Value::Type::BINARY:
413 return *lhs.binary_value_ < *rhs.binary_value_;
414 // TODO(crbug.com/646113): Clean this up when DictionaryValue and ListValue
415 // are completely inlined.
416 case Value::Type::DICTIONARY:
417 return std::lexicographical_compare(
418 std::begin(**lhs.dict_ptr_), std::end(**lhs.dict_ptr_),
419 std::begin(**rhs.dict_ptr_), std::end(**rhs.dict_ptr_),
420 [](const Value::DictStorage::value_type& u,
421 const Value::DictStorage::value_type& v) {
422 return std::tie(u.first, *u.second) < std::tie(v.first, *v.second);
423 });
424 case Value::Type::LIST:
425 return std::lexicographical_compare(
426 std::begin(*lhs.list_), std::end(*lhs.list_), std::begin(*rhs.list_),
427 std::end(*rhs.list_),
428 [](const Value::ListStorage::value_type& u,
429 const Value::ListStorage::value_type& v) { return *u < *v; });
430 }
431
432 NOTREACHED();
433 return false;
434 }
435
operator >(const Value & lhs,const Value & rhs)436 bool operator>(const Value& lhs, const Value& rhs) {
437 return rhs < lhs;
438 }
439
operator <=(const Value & lhs,const Value & rhs)440 bool operator<=(const Value& lhs, const Value& rhs) {
441 return !(rhs < lhs);
442 }
443
operator >=(const Value & lhs,const Value & rhs)444 bool operator>=(const Value& lhs, const Value& rhs) {
445 return !(lhs < rhs);
446 }
447
Equals(const Value * other) const448 bool Value::Equals(const Value* other) const {
449 DCHECK(other);
450 return *this == *other;
451 }
452
453 // static
Equals(const Value * a,const Value * b)454 bool Value::Equals(const Value* a, const Value* b) {
455 if ((a == NULL) && (b == NULL))
456 return true;
457 if ((a == NULL) ^ (b == NULL))
458 return false;
459 return *a == *b;
460 }
461
InternalCopyFundamentalValue(const Value & that)462 void Value::InternalCopyFundamentalValue(const Value& that) {
463 switch (type_) {
464 case Type::NONE:
465 // Nothing to do.
466 return;
467
468 case Type::BOOLEAN:
469 bool_value_ = that.bool_value_;
470 return;
471 case Type::INTEGER:
472 int_value_ = that.int_value_;
473 return;
474 case Type::DOUBLE:
475 double_value_ = that.double_value_;
476 return;
477
478 default:
479 NOTREACHED();
480 }
481 }
482
InternalCopyConstructFrom(const Value & that)483 void Value::InternalCopyConstructFrom(const Value& that) {
484 type_ = that.type_;
485
486 switch (type_) {
487 case Type::NONE:
488 case Type::BOOLEAN:
489 case Type::INTEGER:
490 case Type::DOUBLE:
491 InternalCopyFundamentalValue(that);
492 return;
493
494 case Type::STRING:
495 string_value_.Init(*that.string_value_);
496 return;
497 case Type::BINARY:
498 binary_value_.Init(*that.binary_value_);
499 return;
500 // DictStorage and ListStorage are move-only types due to the presence of
501 // unique_ptrs. This is why the explicit copy of every element is necessary
502 // here.
503 // TODO(crbug.com/646113): Clean this up when DictStorage and ListStorage
504 // can be copied directly.
505 case Type::DICTIONARY:
506 dict_ptr_.Init(MakeUnique<DictStorage>());
507 for (const auto& it : **that.dict_ptr_) {
508 (*dict_ptr_)
509 ->emplace_hint((*dict_ptr_)->end(), it.first,
510 MakeUnique<Value>(*it.second));
511 }
512 return;
513 case Type::LIST:
514 list_.Init();
515 list_->reserve(that.list_->size());
516 for (const auto& it : *that.list_)
517 list_->push_back(MakeUnique<Value>(*it));
518 return;
519 }
520 }
521
InternalMoveConstructFrom(Value && that)522 void Value::InternalMoveConstructFrom(Value&& that) {
523 type_ = that.type_;
524
525 switch (type_) {
526 case Type::NONE:
527 case Type::BOOLEAN:
528 case Type::INTEGER:
529 case Type::DOUBLE:
530 InternalCopyFundamentalValue(that);
531 return;
532
533 case Type::STRING:
534 string_value_.InitFromMove(std::move(that.string_value_));
535 return;
536 case Type::BINARY:
537 binary_value_.InitFromMove(std::move(that.binary_value_));
538 return;
539 case Type::DICTIONARY:
540 dict_ptr_.InitFromMove(std::move(that.dict_ptr_));
541 return;
542 case Type::LIST:
543 list_.InitFromMove(std::move(that.list_));
544 return;
545 }
546 }
547
InternalCopyAssignFromSameType(const Value & that)548 void Value::InternalCopyAssignFromSameType(const Value& that) {
549 // TODO(crbug.com/646113): make this a DCHECK once base::Value does not have
550 // subclasses.
551 CHECK_EQ(type_, that.type_);
552
553 switch (type_) {
554 case Type::NONE:
555 case Type::BOOLEAN:
556 case Type::INTEGER:
557 case Type::DOUBLE:
558 InternalCopyFundamentalValue(that);
559 return;
560
561 case Type::STRING:
562 *string_value_ = *that.string_value_;
563 return;
564 case Type::BINARY:
565 *binary_value_ = *that.binary_value_;
566 return;
567 // DictStorage and ListStorage are move-only types due to the presence of
568 // unique_ptrs. This is why the explicit call to the copy constructor is
569 // necessary here.
570 // TODO(crbug.com/646113): Clean this up when DictStorage and ListStorage
571 // can be copied directly.
572 case Type::DICTIONARY:
573 *dict_ptr_ = std::move(*Value(that).dict_ptr_);
574 return;
575 case Type::LIST:
576 *list_ = std::move(*Value(that).list_);
577 return;
578 }
579 }
580
InternalCleanup()581 void Value::InternalCleanup() {
582 switch (type_) {
583 case Type::NONE:
584 case Type::BOOLEAN:
585 case Type::INTEGER:
586 case Type::DOUBLE:
587 // Nothing to do
588 return;
589
590 case Type::STRING:
591 string_value_.Destroy();
592 return;
593 case Type::BINARY:
594 binary_value_.Destroy();
595 return;
596 case Type::DICTIONARY:
597 dict_ptr_.Destroy();
598 return;
599 case Type::LIST:
600 list_.Destroy();
601 return;
602 }
603 }
604
605 ///////////////////// DictionaryValue ////////////////////
606
607 // static
From(std::unique_ptr<Value> value)608 std::unique_ptr<DictionaryValue> DictionaryValue::From(
609 std::unique_ptr<Value> value) {
610 DictionaryValue* out;
611 if (value && value->GetAsDictionary(&out)) {
612 ignore_result(value.release());
613 return WrapUnique(out);
614 }
615 return nullptr;
616 }
617
DictionaryValue()618 DictionaryValue::DictionaryValue() : Value(Type::DICTIONARY) {}
619
HasKey(StringPiece key) const620 bool DictionaryValue::HasKey(StringPiece key) const {
621 DCHECK(IsStringUTF8(key));
622 auto current_entry = (*dict_ptr_)->find(key.as_string());
623 DCHECK((current_entry == (*dict_ptr_)->end()) || current_entry->second);
624 return current_entry != (*dict_ptr_)->end();
625 }
626
Clear()627 void DictionaryValue::Clear() {
628 (*dict_ptr_)->clear();
629 }
630
Set(StringPiece path,std::unique_ptr<Value> in_value)631 void DictionaryValue::Set(StringPiece path, std::unique_ptr<Value> in_value) {
632 DCHECK(IsStringUTF8(path));
633 DCHECK(in_value);
634
635 StringPiece current_path(path);
636 DictionaryValue* current_dictionary = this;
637 for (size_t delimiter_position = current_path.find('.');
638 delimiter_position != StringPiece::npos;
639 delimiter_position = current_path.find('.')) {
640 // Assume that we're indexing into a dictionary.
641 StringPiece key = current_path.substr(0, delimiter_position);
642 DictionaryValue* child_dictionary = nullptr;
643 if (!current_dictionary->GetDictionary(key, &child_dictionary)) {
644 child_dictionary = new DictionaryValue;
645 current_dictionary->SetWithoutPathExpansion(
646 key, base::WrapUnique(child_dictionary));
647 }
648
649 current_dictionary = child_dictionary;
650 current_path = current_path.substr(delimiter_position + 1);
651 }
652
653 current_dictionary->SetWithoutPathExpansion(current_path,
654 std::move(in_value));
655 }
656
Set(StringPiece path,Value * in_value)657 void DictionaryValue::Set(StringPiece path, Value* in_value) {
658 Set(path, WrapUnique(in_value));
659 }
660
SetBoolean(StringPiece path,bool in_value)661 void DictionaryValue::SetBoolean(StringPiece path, bool in_value) {
662 Set(path, new Value(in_value));
663 }
664
SetInteger(StringPiece path,int in_value)665 void DictionaryValue::SetInteger(StringPiece path, int in_value) {
666 Set(path, new Value(in_value));
667 }
668
SetDouble(StringPiece path,double in_value)669 void DictionaryValue::SetDouble(StringPiece path, double in_value) {
670 Set(path, new Value(in_value));
671 }
672
SetString(StringPiece path,StringPiece in_value)673 void DictionaryValue::SetString(StringPiece path, StringPiece in_value) {
674 Set(path, new Value(in_value));
675 }
676
SetString(StringPiece path,const string16 & in_value)677 void DictionaryValue::SetString(StringPiece path, const string16& in_value) {
678 Set(path, new Value(in_value));
679 }
680
SetWithoutPathExpansion(StringPiece key,std::unique_ptr<Value> in_value)681 void DictionaryValue::SetWithoutPathExpansion(StringPiece key,
682 std::unique_ptr<Value> in_value) {
683 (**dict_ptr_)[key.as_string()] = std::move(in_value);
684 }
685
SetWithoutPathExpansion(StringPiece key,Value * in_value)686 void DictionaryValue::SetWithoutPathExpansion(StringPiece key,
687 Value* in_value) {
688 SetWithoutPathExpansion(key, WrapUnique(in_value));
689 }
690
SetBooleanWithoutPathExpansion(StringPiece path,bool in_value)691 void DictionaryValue::SetBooleanWithoutPathExpansion(StringPiece path,
692 bool in_value) {
693 SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
694 }
695
SetIntegerWithoutPathExpansion(StringPiece path,int in_value)696 void DictionaryValue::SetIntegerWithoutPathExpansion(StringPiece path,
697 int in_value) {
698 SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
699 }
700
SetDoubleWithoutPathExpansion(StringPiece path,double in_value)701 void DictionaryValue::SetDoubleWithoutPathExpansion(StringPiece path,
702 double in_value) {
703 SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
704 }
705
SetStringWithoutPathExpansion(StringPiece path,StringPiece in_value)706 void DictionaryValue::SetStringWithoutPathExpansion(StringPiece path,
707 StringPiece in_value) {
708 SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
709 }
710
SetStringWithoutPathExpansion(StringPiece path,const string16 & in_value)711 void DictionaryValue::SetStringWithoutPathExpansion(StringPiece path,
712 const string16& in_value) {
713 SetWithoutPathExpansion(path, base::MakeUnique<base::Value>(in_value));
714 }
715
Get(StringPiece path,const Value ** out_value) const716 bool DictionaryValue::Get(StringPiece path,
717 const Value** out_value) const {
718 DCHECK(IsStringUTF8(path));
719 StringPiece current_path(path);
720 const DictionaryValue* current_dictionary = this;
721 for (size_t delimiter_position = current_path.find('.');
722 delimiter_position != std::string::npos;
723 delimiter_position = current_path.find('.')) {
724 const DictionaryValue* child_dictionary = NULL;
725 if (!current_dictionary->GetDictionaryWithoutPathExpansion(
726 current_path.substr(0, delimiter_position), &child_dictionary)) {
727 return false;
728 }
729
730 current_dictionary = child_dictionary;
731 current_path = current_path.substr(delimiter_position + 1);
732 }
733
734 return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
735 }
736
Get(StringPiece path,Value ** out_value)737 bool DictionaryValue::Get(StringPiece path, Value** out_value) {
738 return static_cast<const DictionaryValue&>(*this).Get(
739 path,
740 const_cast<const Value**>(out_value));
741 }
742
GetBoolean(StringPiece path,bool * bool_value) const743 bool DictionaryValue::GetBoolean(StringPiece path, bool* bool_value) const {
744 const Value* value;
745 if (!Get(path, &value))
746 return false;
747
748 return value->GetAsBoolean(bool_value);
749 }
750
GetInteger(StringPiece path,int * out_value) const751 bool DictionaryValue::GetInteger(StringPiece path, int* out_value) const {
752 const Value* value;
753 if (!Get(path, &value))
754 return false;
755
756 return value->GetAsInteger(out_value);
757 }
758
GetDouble(StringPiece path,double * out_value) const759 bool DictionaryValue::GetDouble(StringPiece path, double* out_value) const {
760 const Value* value;
761 if (!Get(path, &value))
762 return false;
763
764 return value->GetAsDouble(out_value);
765 }
766
GetString(StringPiece path,std::string * out_value) const767 bool DictionaryValue::GetString(StringPiece path,
768 std::string* out_value) const {
769 const Value* value;
770 if (!Get(path, &value))
771 return false;
772
773 return value->GetAsString(out_value);
774 }
775
GetString(StringPiece path,string16 * out_value) const776 bool DictionaryValue::GetString(StringPiece path, string16* out_value) const {
777 const Value* value;
778 if (!Get(path, &value))
779 return false;
780
781 return value->GetAsString(out_value);
782 }
783
GetStringASCII(StringPiece path,std::string * out_value) const784 bool DictionaryValue::GetStringASCII(StringPiece path,
785 std::string* out_value) const {
786 std::string out;
787 if (!GetString(path, &out))
788 return false;
789
790 if (!IsStringASCII(out)) {
791 NOTREACHED();
792 return false;
793 }
794
795 out_value->assign(out);
796 return true;
797 }
798
GetBinary(StringPiece path,const BinaryValue ** out_value) const799 bool DictionaryValue::GetBinary(StringPiece path,
800 const BinaryValue** out_value) const {
801 const Value* value;
802 bool result = Get(path, &value);
803 if (!result || !value->IsType(Type::BINARY))
804 return false;
805
806 if (out_value)
807 *out_value = value;
808
809 return true;
810 }
811
GetBinary(StringPiece path,BinaryValue ** out_value)812 bool DictionaryValue::GetBinary(StringPiece path, BinaryValue** out_value) {
813 return static_cast<const DictionaryValue&>(*this).GetBinary(
814 path,
815 const_cast<const BinaryValue**>(out_value));
816 }
817
GetDictionary(StringPiece path,const DictionaryValue ** out_value) const818 bool DictionaryValue::GetDictionary(StringPiece path,
819 const DictionaryValue** out_value) const {
820 const Value* value;
821 bool result = Get(path, &value);
822 if (!result || !value->IsType(Type::DICTIONARY))
823 return false;
824
825 if (out_value)
826 *out_value = static_cast<const DictionaryValue*>(value);
827
828 return true;
829 }
830
GetDictionary(StringPiece path,DictionaryValue ** out_value)831 bool DictionaryValue::GetDictionary(StringPiece path,
832 DictionaryValue** out_value) {
833 return static_cast<const DictionaryValue&>(*this).GetDictionary(
834 path,
835 const_cast<const DictionaryValue**>(out_value));
836 }
837
GetList(StringPiece path,const ListValue ** out_value) const838 bool DictionaryValue::GetList(StringPiece path,
839 const ListValue** out_value) const {
840 const Value* value;
841 bool result = Get(path, &value);
842 if (!result || !value->IsType(Type::LIST))
843 return false;
844
845 if (out_value)
846 *out_value = static_cast<const ListValue*>(value);
847
848 return true;
849 }
850
GetList(StringPiece path,ListValue ** out_value)851 bool DictionaryValue::GetList(StringPiece path, ListValue** out_value) {
852 return static_cast<const DictionaryValue&>(*this).GetList(
853 path,
854 const_cast<const ListValue**>(out_value));
855 }
856
GetWithoutPathExpansion(StringPiece key,const Value ** out_value) const857 bool DictionaryValue::GetWithoutPathExpansion(StringPiece key,
858 const Value** out_value) const {
859 DCHECK(IsStringUTF8(key));
860 auto entry_iterator = (*dict_ptr_)->find(key.as_string());
861 if (entry_iterator == (*dict_ptr_)->end())
862 return false;
863
864 if (out_value)
865 *out_value = entry_iterator->second.get();
866 return true;
867 }
868
GetWithoutPathExpansion(StringPiece key,Value ** out_value)869 bool DictionaryValue::GetWithoutPathExpansion(StringPiece key,
870 Value** out_value) {
871 return static_cast<const DictionaryValue&>(*this).GetWithoutPathExpansion(
872 key,
873 const_cast<const Value**>(out_value));
874 }
875
GetBooleanWithoutPathExpansion(StringPiece key,bool * out_value) const876 bool DictionaryValue::GetBooleanWithoutPathExpansion(StringPiece key,
877 bool* out_value) const {
878 const Value* value;
879 if (!GetWithoutPathExpansion(key, &value))
880 return false;
881
882 return value->GetAsBoolean(out_value);
883 }
884
GetIntegerWithoutPathExpansion(StringPiece key,int * out_value) const885 bool DictionaryValue::GetIntegerWithoutPathExpansion(StringPiece key,
886 int* out_value) const {
887 const Value* value;
888 if (!GetWithoutPathExpansion(key, &value))
889 return false;
890
891 return value->GetAsInteger(out_value);
892 }
893
GetDoubleWithoutPathExpansion(StringPiece key,double * out_value) const894 bool DictionaryValue::GetDoubleWithoutPathExpansion(StringPiece key,
895 double* out_value) const {
896 const Value* value;
897 if (!GetWithoutPathExpansion(key, &value))
898 return false;
899
900 return value->GetAsDouble(out_value);
901 }
902
GetStringWithoutPathExpansion(StringPiece key,std::string * out_value) const903 bool DictionaryValue::GetStringWithoutPathExpansion(
904 StringPiece key,
905 std::string* out_value) const {
906 const Value* value;
907 if (!GetWithoutPathExpansion(key, &value))
908 return false;
909
910 return value->GetAsString(out_value);
911 }
912
GetStringWithoutPathExpansion(StringPiece key,string16 * out_value) const913 bool DictionaryValue::GetStringWithoutPathExpansion(StringPiece key,
914 string16* out_value) const {
915 const Value* value;
916 if (!GetWithoutPathExpansion(key, &value))
917 return false;
918
919 return value->GetAsString(out_value);
920 }
921
GetDictionaryWithoutPathExpansion(StringPiece key,const DictionaryValue ** out_value) const922 bool DictionaryValue::GetDictionaryWithoutPathExpansion(
923 StringPiece key,
924 const DictionaryValue** out_value) const {
925 const Value* value;
926 bool result = GetWithoutPathExpansion(key, &value);
927 if (!result || !value->IsType(Type::DICTIONARY))
928 return false;
929
930 if (out_value)
931 *out_value = static_cast<const DictionaryValue*>(value);
932
933 return true;
934 }
935
GetDictionaryWithoutPathExpansion(StringPiece key,DictionaryValue ** out_value)936 bool DictionaryValue::GetDictionaryWithoutPathExpansion(
937 StringPiece key,
938 DictionaryValue** out_value) {
939 const DictionaryValue& const_this =
940 static_cast<const DictionaryValue&>(*this);
941 return const_this.GetDictionaryWithoutPathExpansion(
942 key,
943 const_cast<const DictionaryValue**>(out_value));
944 }
945
GetListWithoutPathExpansion(StringPiece key,const ListValue ** out_value) const946 bool DictionaryValue::GetListWithoutPathExpansion(
947 StringPiece key,
948 const ListValue** out_value) const {
949 const Value* value;
950 bool result = GetWithoutPathExpansion(key, &value);
951 if (!result || !value->IsType(Type::LIST))
952 return false;
953
954 if (out_value)
955 *out_value = static_cast<const ListValue*>(value);
956
957 return true;
958 }
959
GetListWithoutPathExpansion(StringPiece key,ListValue ** out_value)960 bool DictionaryValue::GetListWithoutPathExpansion(StringPiece key,
961 ListValue** out_value) {
962 return
963 static_cast<const DictionaryValue&>(*this).GetListWithoutPathExpansion(
964 key,
965 const_cast<const ListValue**>(out_value));
966 }
967
Remove(StringPiece path,std::unique_ptr<Value> * out_value)968 bool DictionaryValue::Remove(StringPiece path,
969 std::unique_ptr<Value>* out_value) {
970 DCHECK(IsStringUTF8(path));
971 StringPiece current_path(path);
972 DictionaryValue* current_dictionary = this;
973 size_t delimiter_position = current_path.rfind('.');
974 if (delimiter_position != StringPiece::npos) {
975 if (!GetDictionary(current_path.substr(0, delimiter_position),
976 ¤t_dictionary))
977 return false;
978 current_path = current_path.substr(delimiter_position + 1);
979 }
980
981 return current_dictionary->RemoveWithoutPathExpansion(current_path,
982 out_value);
983 }
984
RemoveWithoutPathExpansion(StringPiece key,std::unique_ptr<Value> * out_value)985 bool DictionaryValue::RemoveWithoutPathExpansion(
986 StringPiece key,
987 std::unique_ptr<Value>* out_value) {
988 DCHECK(IsStringUTF8(key));
989 auto entry_iterator = (*dict_ptr_)->find(key.as_string());
990 if (entry_iterator == (*dict_ptr_)->end())
991 return false;
992
993 if (out_value)
994 *out_value = std::move(entry_iterator->second);
995 (*dict_ptr_)->erase(entry_iterator);
996 return true;
997 }
998
RemovePath(StringPiece path,std::unique_ptr<Value> * out_value)999 bool DictionaryValue::RemovePath(StringPiece path,
1000 std::unique_ptr<Value>* out_value) {
1001 bool result = false;
1002 size_t delimiter_position = path.find('.');
1003
1004 if (delimiter_position == std::string::npos)
1005 return RemoveWithoutPathExpansion(path, out_value);
1006
1007 StringPiece subdict_path = path.substr(0, delimiter_position);
1008 DictionaryValue* subdict = NULL;
1009 if (!GetDictionary(subdict_path, &subdict))
1010 return false;
1011 result = subdict->RemovePath(path.substr(delimiter_position + 1),
1012 out_value);
1013 if (result && subdict->empty())
1014 RemoveWithoutPathExpansion(subdict_path, NULL);
1015
1016 return result;
1017 }
1018
DeepCopyWithoutEmptyChildren() const1019 std::unique_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren()
1020 const {
1021 std::unique_ptr<DictionaryValue> copy =
1022 CopyDictionaryWithoutEmptyChildren(*this);
1023 if (!copy)
1024 copy.reset(new DictionaryValue);
1025 return copy;
1026 }
1027
MergeDictionary(const DictionaryValue * dictionary)1028 void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
1029 CHECK(dictionary->is_dict());
1030 for (DictionaryValue::Iterator it(*dictionary); !it.IsAtEnd(); it.Advance()) {
1031 const Value* merge_value = &it.value();
1032 // Check whether we have to merge dictionaries.
1033 if (merge_value->IsType(Value::Type::DICTIONARY)) {
1034 DictionaryValue* sub_dict;
1035 if (GetDictionaryWithoutPathExpansion(it.key(), &sub_dict)) {
1036 sub_dict->MergeDictionary(
1037 static_cast<const DictionaryValue*>(merge_value));
1038 continue;
1039 }
1040 }
1041 // All other cases: Make a copy and hook it up.
1042 SetWithoutPathExpansion(it.key(), MakeUnique<Value>(*merge_value));
1043 }
1044 }
1045
Swap(DictionaryValue * other)1046 void DictionaryValue::Swap(DictionaryValue* other) {
1047 CHECK(other->is_dict());
1048 dict_ptr_->swap(*(other->dict_ptr_));
1049 }
1050
Iterator(const DictionaryValue & target)1051 DictionaryValue::Iterator::Iterator(const DictionaryValue& target)
1052 : target_(target), it_((*target.dict_ptr_)->begin()) {}
1053
1054 DictionaryValue::Iterator::Iterator(const Iterator& other) = default;
1055
~Iterator()1056 DictionaryValue::Iterator::~Iterator() {}
1057
DeepCopy() const1058 DictionaryValue* DictionaryValue::DeepCopy() const {
1059 return new DictionaryValue(*this);
1060 }
1061
CreateDeepCopy() const1062 std::unique_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const {
1063 return MakeUnique<DictionaryValue>(*this);
1064 }
1065
1066 ///////////////////// ListValue ////////////////////
1067
1068 // static
From(std::unique_ptr<Value> value)1069 std::unique_ptr<ListValue> ListValue::From(std::unique_ptr<Value> value) {
1070 ListValue* out;
1071 if (value && value->GetAsList(&out)) {
1072 ignore_result(value.release());
1073 return WrapUnique(out);
1074 }
1075 return nullptr;
1076 }
1077
ListValue()1078 ListValue::ListValue() : Value(Type::LIST) {}
1079
Clear()1080 void ListValue::Clear() {
1081 list_->clear();
1082 }
1083
Set(size_t index,Value * in_value)1084 bool ListValue::Set(size_t index, Value* in_value) {
1085 return Set(index, WrapUnique(in_value));
1086 }
1087
Set(size_t index,std::unique_ptr<Value> in_value)1088 bool ListValue::Set(size_t index, std::unique_ptr<Value> in_value) {
1089 if (!in_value)
1090 return false;
1091
1092 if (index >= list_->size()) {
1093 // Pad out any intermediate indexes with null settings
1094 while (index > list_->size())
1095 Append(CreateNullValue());
1096 Append(std::move(in_value));
1097 } else {
1098 // TODO(dcheng): remove this DCHECK once the raw pointer version is removed?
1099 DCHECK((*list_)[index] != in_value);
1100 (*list_)[index] = std::move(in_value);
1101 }
1102 return true;
1103 }
1104
Get(size_t index,const Value ** out_value) const1105 bool ListValue::Get(size_t index, const Value** out_value) const {
1106 if (index >= list_->size())
1107 return false;
1108
1109 if (out_value)
1110 *out_value = (*list_)[index].get();
1111
1112 return true;
1113 }
1114
Get(size_t index,Value ** out_value)1115 bool ListValue::Get(size_t index, Value** out_value) {
1116 return static_cast<const ListValue&>(*this).Get(
1117 index,
1118 const_cast<const Value**>(out_value));
1119 }
1120
GetBoolean(size_t index,bool * bool_value) const1121 bool ListValue::GetBoolean(size_t index, bool* bool_value) const {
1122 const Value* value;
1123 if (!Get(index, &value))
1124 return false;
1125
1126 return value->GetAsBoolean(bool_value);
1127 }
1128
GetInteger(size_t index,int * out_value) const1129 bool ListValue::GetInteger(size_t index, int* out_value) const {
1130 const Value* value;
1131 if (!Get(index, &value))
1132 return false;
1133
1134 return value->GetAsInteger(out_value);
1135 }
1136
GetDouble(size_t index,double * out_value) const1137 bool ListValue::GetDouble(size_t index, double* out_value) const {
1138 const Value* value;
1139 if (!Get(index, &value))
1140 return false;
1141
1142 return value->GetAsDouble(out_value);
1143 }
1144
GetString(size_t index,std::string * out_value) const1145 bool ListValue::GetString(size_t index, std::string* out_value) const {
1146 const Value* value;
1147 if (!Get(index, &value))
1148 return false;
1149
1150 return value->GetAsString(out_value);
1151 }
1152
GetString(size_t index,string16 * out_value) const1153 bool ListValue::GetString(size_t index, string16* out_value) const {
1154 const Value* value;
1155 if (!Get(index, &value))
1156 return false;
1157
1158 return value->GetAsString(out_value);
1159 }
1160
GetBinary(size_t index,const BinaryValue ** out_value) const1161 bool ListValue::GetBinary(size_t index, const BinaryValue** out_value) const {
1162 const Value* value;
1163 bool result = Get(index, &value);
1164 if (!result || !value->IsType(Type::BINARY))
1165 return false;
1166
1167 if (out_value)
1168 *out_value = value;
1169
1170 return true;
1171 }
1172
GetBinary(size_t index,BinaryValue ** out_value)1173 bool ListValue::GetBinary(size_t index, BinaryValue** out_value) {
1174 return static_cast<const ListValue&>(*this).GetBinary(
1175 index,
1176 const_cast<const BinaryValue**>(out_value));
1177 }
1178
GetDictionary(size_t index,const DictionaryValue ** out_value) const1179 bool ListValue::GetDictionary(size_t index,
1180 const DictionaryValue** out_value) const {
1181 const Value* value;
1182 bool result = Get(index, &value);
1183 if (!result || !value->IsType(Type::DICTIONARY))
1184 return false;
1185
1186 if (out_value)
1187 *out_value = static_cast<const DictionaryValue*>(value);
1188
1189 return true;
1190 }
1191
GetDictionary(size_t index,DictionaryValue ** out_value)1192 bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) {
1193 return static_cast<const ListValue&>(*this).GetDictionary(
1194 index,
1195 const_cast<const DictionaryValue**>(out_value));
1196 }
1197
GetList(size_t index,const ListValue ** out_value) const1198 bool ListValue::GetList(size_t index, const ListValue** out_value) const {
1199 const Value* value;
1200 bool result = Get(index, &value);
1201 if (!result || !value->IsType(Type::LIST))
1202 return false;
1203
1204 if (out_value)
1205 *out_value = static_cast<const ListValue*>(value);
1206
1207 return true;
1208 }
1209
GetList(size_t index,ListValue ** out_value)1210 bool ListValue::GetList(size_t index, ListValue** out_value) {
1211 return static_cast<const ListValue&>(*this).GetList(
1212 index,
1213 const_cast<const ListValue**>(out_value));
1214 }
1215
Remove(size_t index,std::unique_ptr<Value> * out_value)1216 bool ListValue::Remove(size_t index, std::unique_ptr<Value>* out_value) {
1217 if (index >= list_->size())
1218 return false;
1219
1220 if (out_value)
1221 *out_value = std::move((*list_)[index]);
1222
1223 list_->erase(list_->begin() + index);
1224 return true;
1225 }
1226
Remove(const Value & value,size_t * index)1227 bool ListValue::Remove(const Value& value, size_t* index) {
1228 for (auto it = list_->begin(); it != list_->end(); ++it) {
1229 if (**it == value) {
1230 size_t previous_index = it - list_->begin();
1231 list_->erase(it);
1232
1233 if (index)
1234 *index = previous_index;
1235 return true;
1236 }
1237 }
1238 return false;
1239 }
1240
Erase(iterator iter,std::unique_ptr<Value> * out_value)1241 ListValue::iterator ListValue::Erase(iterator iter,
1242 std::unique_ptr<Value>* out_value) {
1243 if (out_value)
1244 *out_value = std::move(*ListStorage::iterator(iter));
1245
1246 return list_->erase(iter);
1247 }
1248
Append(std::unique_ptr<Value> in_value)1249 void ListValue::Append(std::unique_ptr<Value> in_value) {
1250 list_->push_back(std::move(in_value));
1251 }
1252
1253 #if !defined(OS_LINUX)
Append(Value * in_value)1254 void ListValue::Append(Value* in_value) {
1255 DCHECK(in_value);
1256 Append(WrapUnique(in_value));
1257 }
1258 #endif
1259
AppendBoolean(bool in_value)1260 void ListValue::AppendBoolean(bool in_value) {
1261 Append(MakeUnique<Value>(in_value));
1262 }
1263
AppendInteger(int in_value)1264 void ListValue::AppendInteger(int in_value) {
1265 Append(MakeUnique<Value>(in_value));
1266 }
1267
AppendDouble(double in_value)1268 void ListValue::AppendDouble(double in_value) {
1269 Append(MakeUnique<Value>(in_value));
1270 }
1271
AppendString(StringPiece in_value)1272 void ListValue::AppendString(StringPiece in_value) {
1273 Append(MakeUnique<Value>(in_value));
1274 }
1275
AppendString(const string16 & in_value)1276 void ListValue::AppendString(const string16& in_value) {
1277 Append(MakeUnique<Value>(in_value));
1278 }
1279
AppendStrings(const std::vector<std::string> & in_values)1280 void ListValue::AppendStrings(const std::vector<std::string>& in_values) {
1281 for (std::vector<std::string>::const_iterator it = in_values.begin();
1282 it != in_values.end(); ++it) {
1283 AppendString(*it);
1284 }
1285 }
1286
AppendStrings(const std::vector<string16> & in_values)1287 void ListValue::AppendStrings(const std::vector<string16>& in_values) {
1288 for (std::vector<string16>::const_iterator it = in_values.begin();
1289 it != in_values.end(); ++it) {
1290 AppendString(*it);
1291 }
1292 }
1293
AppendIfNotPresent(std::unique_ptr<Value> in_value)1294 bool ListValue::AppendIfNotPresent(std::unique_ptr<Value> in_value) {
1295 DCHECK(in_value);
1296 for (const auto& entry : *list_) {
1297 if (*entry == *in_value)
1298 return false;
1299 }
1300 list_->push_back(std::move(in_value));
1301 return true;
1302 }
1303
Insert(size_t index,std::unique_ptr<Value> in_value)1304 bool ListValue::Insert(size_t index, std::unique_ptr<Value> in_value) {
1305 DCHECK(in_value);
1306 if (index > list_->size())
1307 return false;
1308
1309 list_->insert(list_->begin() + index, std::move(in_value));
1310 return true;
1311 }
1312
Find(const Value & value) const1313 ListValue::const_iterator ListValue::Find(const Value& value) const {
1314 return std::find_if(list_->begin(), list_->end(),
1315 [&value](const std::unique_ptr<Value>& entry) {
1316 return *entry == value;
1317 });
1318 }
1319
Swap(ListValue * other)1320 void ListValue::Swap(ListValue* other) {
1321 CHECK(other->is_list());
1322 list_->swap(*(other->list_));
1323 }
1324
DeepCopy() const1325 ListValue* ListValue::DeepCopy() const {
1326 return new ListValue(*this);
1327 }
1328
CreateDeepCopy() const1329 std::unique_ptr<ListValue> ListValue::CreateDeepCopy() const {
1330 return MakeUnique<ListValue>(*this);
1331 }
1332
~ValueSerializer()1333 ValueSerializer::~ValueSerializer() {
1334 }
1335
~ValueDeserializer()1336 ValueDeserializer::~ValueDeserializer() {
1337 }
1338
operator <<(std::ostream & out,const Value & value)1339 std::ostream& operator<<(std::ostream& out, const Value& value) {
1340 std::string json;
1341 JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json);
1342 return out << json;
1343 }
1344
operator <<(std::ostream & out,const Value::Type & type)1345 std::ostream& operator<<(std::ostream& out, const Value::Type& type) {
1346 if (static_cast<int>(type) < 0 ||
1347 static_cast<size_t>(type) >= arraysize(kTypeNames))
1348 return out << "Invalid Type (index = " << static_cast<int>(type) << ")";
1349 return out << Value::GetTypeName(type);
1350 }
1351
1352 } // namespace base
1353