1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/json/json_writer.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
8*635a8641SAndroid Build Coastguard Worker
9*635a8641SAndroid Build Coastguard Worker #include <cmath>
10*635a8641SAndroid Build Coastguard Worker #include <limits>
11*635a8641SAndroid Build Coastguard Worker
12*635a8641SAndroid Build Coastguard Worker #include "base/json/string_escape.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/values.h"
17*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
18*635a8641SAndroid Build Coastguard Worker
19*635a8641SAndroid Build Coastguard Worker namespace base {
20*635a8641SAndroid Build Coastguard Worker
21*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN)
22*635a8641SAndroid Build Coastguard Worker const char kPrettyPrintLineEnding[] = "\r\n";
23*635a8641SAndroid Build Coastguard Worker #else
24*635a8641SAndroid Build Coastguard Worker const char kPrettyPrintLineEnding[] = "\n";
25*635a8641SAndroid Build Coastguard Worker #endif
26*635a8641SAndroid Build Coastguard Worker
27*635a8641SAndroid Build Coastguard Worker // static
Write(const Value & node,std::string * json)28*635a8641SAndroid Build Coastguard Worker bool JSONWriter::Write(const Value& node, std::string* json) {
29*635a8641SAndroid Build Coastguard Worker return WriteWithOptions(node, 0, json);
30*635a8641SAndroid Build Coastguard Worker }
31*635a8641SAndroid Build Coastguard Worker
32*635a8641SAndroid Build Coastguard Worker // static
WriteWithOptions(const Value & node,int options,std::string * json)33*635a8641SAndroid Build Coastguard Worker bool JSONWriter::WriteWithOptions(const Value& node,
34*635a8641SAndroid Build Coastguard Worker int options,
35*635a8641SAndroid Build Coastguard Worker std::string* json) {
36*635a8641SAndroid Build Coastguard Worker json->clear();
37*635a8641SAndroid Build Coastguard Worker // Is there a better way to estimate the size of the output?
38*635a8641SAndroid Build Coastguard Worker json->reserve(1024);
39*635a8641SAndroid Build Coastguard Worker
40*635a8641SAndroid Build Coastguard Worker JSONWriter writer(options, json);
41*635a8641SAndroid Build Coastguard Worker bool result = writer.BuildJSONString(node, 0U);
42*635a8641SAndroid Build Coastguard Worker
43*635a8641SAndroid Build Coastguard Worker if (options & OPTIONS_PRETTY_PRINT)
44*635a8641SAndroid Build Coastguard Worker json->append(kPrettyPrintLineEnding);
45*635a8641SAndroid Build Coastguard Worker
46*635a8641SAndroid Build Coastguard Worker return result;
47*635a8641SAndroid Build Coastguard Worker }
48*635a8641SAndroid Build Coastguard Worker
JSONWriter(int options,std::string * json)49*635a8641SAndroid Build Coastguard Worker JSONWriter::JSONWriter(int options, std::string* json)
50*635a8641SAndroid Build Coastguard Worker : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0),
51*635a8641SAndroid Build Coastguard Worker omit_double_type_preservation_(
52*635a8641SAndroid Build Coastguard Worker (options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION) != 0),
53*635a8641SAndroid Build Coastguard Worker pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0),
54*635a8641SAndroid Build Coastguard Worker json_string_(json) {
55*635a8641SAndroid Build Coastguard Worker DCHECK(json);
56*635a8641SAndroid Build Coastguard Worker }
57*635a8641SAndroid Build Coastguard Worker
BuildJSONString(const Value & node,size_t depth)58*635a8641SAndroid Build Coastguard Worker bool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
59*635a8641SAndroid Build Coastguard Worker switch (node.type()) {
60*635a8641SAndroid Build Coastguard Worker case Value::Type::NONE: {
61*635a8641SAndroid Build Coastguard Worker json_string_->append("null");
62*635a8641SAndroid Build Coastguard Worker return true;
63*635a8641SAndroid Build Coastguard Worker }
64*635a8641SAndroid Build Coastguard Worker
65*635a8641SAndroid Build Coastguard Worker case Value::Type::BOOLEAN: {
66*635a8641SAndroid Build Coastguard Worker bool value;
67*635a8641SAndroid Build Coastguard Worker bool result = node.GetAsBoolean(&value);
68*635a8641SAndroid Build Coastguard Worker DCHECK(result);
69*635a8641SAndroid Build Coastguard Worker json_string_->append(value ? "true" : "false");
70*635a8641SAndroid Build Coastguard Worker return result;
71*635a8641SAndroid Build Coastguard Worker }
72*635a8641SAndroid Build Coastguard Worker
73*635a8641SAndroid Build Coastguard Worker case Value::Type::INTEGER: {
74*635a8641SAndroid Build Coastguard Worker int value;
75*635a8641SAndroid Build Coastguard Worker bool result = node.GetAsInteger(&value);
76*635a8641SAndroid Build Coastguard Worker DCHECK(result);
77*635a8641SAndroid Build Coastguard Worker json_string_->append(IntToString(value));
78*635a8641SAndroid Build Coastguard Worker return result;
79*635a8641SAndroid Build Coastguard Worker }
80*635a8641SAndroid Build Coastguard Worker
81*635a8641SAndroid Build Coastguard Worker case Value::Type::DOUBLE: {
82*635a8641SAndroid Build Coastguard Worker double value;
83*635a8641SAndroid Build Coastguard Worker bool result = node.GetAsDouble(&value);
84*635a8641SAndroid Build Coastguard Worker DCHECK(result);
85*635a8641SAndroid Build Coastguard Worker if (omit_double_type_preservation_ &&
86*635a8641SAndroid Build Coastguard Worker value <= std::numeric_limits<int64_t>::max() &&
87*635a8641SAndroid Build Coastguard Worker value >= std::numeric_limits<int64_t>::min() &&
88*635a8641SAndroid Build Coastguard Worker std::floor(value) == value) {
89*635a8641SAndroid Build Coastguard Worker json_string_->append(Int64ToString(static_cast<int64_t>(value)));
90*635a8641SAndroid Build Coastguard Worker return result;
91*635a8641SAndroid Build Coastguard Worker }
92*635a8641SAndroid Build Coastguard Worker std::string real = NumberToString(value);
93*635a8641SAndroid Build Coastguard Worker // Ensure that the number has a .0 if there's no decimal or 'e'. This
94*635a8641SAndroid Build Coastguard Worker // makes sure that when we read the JSON back, it's interpreted as a
95*635a8641SAndroid Build Coastguard Worker // real rather than an int.
96*635a8641SAndroid Build Coastguard Worker if (real.find('.') == std::string::npos &&
97*635a8641SAndroid Build Coastguard Worker real.find('e') == std::string::npos &&
98*635a8641SAndroid Build Coastguard Worker real.find('E') == std::string::npos) {
99*635a8641SAndroid Build Coastguard Worker real.append(".0");
100*635a8641SAndroid Build Coastguard Worker }
101*635a8641SAndroid Build Coastguard Worker // The JSON spec requires that non-integer values in the range (-1,1)
102*635a8641SAndroid Build Coastguard Worker // have a zero before the decimal point - ".52" is not valid, "0.52" is.
103*635a8641SAndroid Build Coastguard Worker if (real[0] == '.') {
104*635a8641SAndroid Build Coastguard Worker real.insert(static_cast<size_t>(0), static_cast<size_t>(1), '0');
105*635a8641SAndroid Build Coastguard Worker } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
106*635a8641SAndroid Build Coastguard Worker // "-.1" bad "-0.1" good
107*635a8641SAndroid Build Coastguard Worker real.insert(static_cast<size_t>(1), static_cast<size_t>(1), '0');
108*635a8641SAndroid Build Coastguard Worker }
109*635a8641SAndroid Build Coastguard Worker json_string_->append(real);
110*635a8641SAndroid Build Coastguard Worker return result;
111*635a8641SAndroid Build Coastguard Worker }
112*635a8641SAndroid Build Coastguard Worker
113*635a8641SAndroid Build Coastguard Worker case Value::Type::STRING: {
114*635a8641SAndroid Build Coastguard Worker std::string value;
115*635a8641SAndroid Build Coastguard Worker bool result = node.GetAsString(&value);
116*635a8641SAndroid Build Coastguard Worker DCHECK(result);
117*635a8641SAndroid Build Coastguard Worker EscapeJSONString(value, true, json_string_);
118*635a8641SAndroid Build Coastguard Worker return result;
119*635a8641SAndroid Build Coastguard Worker }
120*635a8641SAndroid Build Coastguard Worker
121*635a8641SAndroid Build Coastguard Worker case Value::Type::LIST: {
122*635a8641SAndroid Build Coastguard Worker json_string_->push_back('[');
123*635a8641SAndroid Build Coastguard Worker if (pretty_print_)
124*635a8641SAndroid Build Coastguard Worker json_string_->push_back(' ');
125*635a8641SAndroid Build Coastguard Worker
126*635a8641SAndroid Build Coastguard Worker const ListValue* list = nullptr;
127*635a8641SAndroid Build Coastguard Worker bool first_value_has_been_output = false;
128*635a8641SAndroid Build Coastguard Worker bool result = node.GetAsList(&list);
129*635a8641SAndroid Build Coastguard Worker DCHECK(result);
130*635a8641SAndroid Build Coastguard Worker for (const auto& value : *list) {
131*635a8641SAndroid Build Coastguard Worker if (omit_binary_values_ && value.type() == Value::Type::BINARY)
132*635a8641SAndroid Build Coastguard Worker continue;
133*635a8641SAndroid Build Coastguard Worker
134*635a8641SAndroid Build Coastguard Worker if (first_value_has_been_output) {
135*635a8641SAndroid Build Coastguard Worker json_string_->push_back(',');
136*635a8641SAndroid Build Coastguard Worker if (pretty_print_)
137*635a8641SAndroid Build Coastguard Worker json_string_->push_back(' ');
138*635a8641SAndroid Build Coastguard Worker }
139*635a8641SAndroid Build Coastguard Worker
140*635a8641SAndroid Build Coastguard Worker if (!BuildJSONString(value, depth))
141*635a8641SAndroid Build Coastguard Worker result = false;
142*635a8641SAndroid Build Coastguard Worker
143*635a8641SAndroid Build Coastguard Worker first_value_has_been_output = true;
144*635a8641SAndroid Build Coastguard Worker }
145*635a8641SAndroid Build Coastguard Worker
146*635a8641SAndroid Build Coastguard Worker if (pretty_print_)
147*635a8641SAndroid Build Coastguard Worker json_string_->push_back(' ');
148*635a8641SAndroid Build Coastguard Worker json_string_->push_back(']');
149*635a8641SAndroid Build Coastguard Worker return result;
150*635a8641SAndroid Build Coastguard Worker }
151*635a8641SAndroid Build Coastguard Worker
152*635a8641SAndroid Build Coastguard Worker case Value::Type::DICTIONARY: {
153*635a8641SAndroid Build Coastguard Worker json_string_->push_back('{');
154*635a8641SAndroid Build Coastguard Worker if (pretty_print_)
155*635a8641SAndroid Build Coastguard Worker json_string_->append(kPrettyPrintLineEnding);
156*635a8641SAndroid Build Coastguard Worker
157*635a8641SAndroid Build Coastguard Worker const DictionaryValue* dict = nullptr;
158*635a8641SAndroid Build Coastguard Worker bool first_value_has_been_output = false;
159*635a8641SAndroid Build Coastguard Worker bool result = node.GetAsDictionary(&dict);
160*635a8641SAndroid Build Coastguard Worker DCHECK(result);
161*635a8641SAndroid Build Coastguard Worker for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
162*635a8641SAndroid Build Coastguard Worker itr.Advance()) {
163*635a8641SAndroid Build Coastguard Worker if (omit_binary_values_ && itr.value().type() == Value::Type::BINARY) {
164*635a8641SAndroid Build Coastguard Worker continue;
165*635a8641SAndroid Build Coastguard Worker }
166*635a8641SAndroid Build Coastguard Worker
167*635a8641SAndroid Build Coastguard Worker if (first_value_has_been_output) {
168*635a8641SAndroid Build Coastguard Worker json_string_->push_back(',');
169*635a8641SAndroid Build Coastguard Worker if (pretty_print_)
170*635a8641SAndroid Build Coastguard Worker json_string_->append(kPrettyPrintLineEnding);
171*635a8641SAndroid Build Coastguard Worker }
172*635a8641SAndroid Build Coastguard Worker
173*635a8641SAndroid Build Coastguard Worker if (pretty_print_)
174*635a8641SAndroid Build Coastguard Worker IndentLine(depth + 1U);
175*635a8641SAndroid Build Coastguard Worker
176*635a8641SAndroid Build Coastguard Worker EscapeJSONString(itr.key(), true, json_string_);
177*635a8641SAndroid Build Coastguard Worker json_string_->push_back(':');
178*635a8641SAndroid Build Coastguard Worker if (pretty_print_)
179*635a8641SAndroid Build Coastguard Worker json_string_->push_back(' ');
180*635a8641SAndroid Build Coastguard Worker
181*635a8641SAndroid Build Coastguard Worker if (!BuildJSONString(itr.value(), depth + 1U))
182*635a8641SAndroid Build Coastguard Worker result = false;
183*635a8641SAndroid Build Coastguard Worker
184*635a8641SAndroid Build Coastguard Worker first_value_has_been_output = true;
185*635a8641SAndroid Build Coastguard Worker }
186*635a8641SAndroid Build Coastguard Worker
187*635a8641SAndroid Build Coastguard Worker if (pretty_print_) {
188*635a8641SAndroid Build Coastguard Worker json_string_->append(kPrettyPrintLineEnding);
189*635a8641SAndroid Build Coastguard Worker IndentLine(depth);
190*635a8641SAndroid Build Coastguard Worker }
191*635a8641SAndroid Build Coastguard Worker
192*635a8641SAndroid Build Coastguard Worker json_string_->push_back('}');
193*635a8641SAndroid Build Coastguard Worker return result;
194*635a8641SAndroid Build Coastguard Worker }
195*635a8641SAndroid Build Coastguard Worker
196*635a8641SAndroid Build Coastguard Worker case Value::Type::BINARY:
197*635a8641SAndroid Build Coastguard Worker // Successful only if we're allowed to omit it.
198*635a8641SAndroid Build Coastguard Worker DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
199*635a8641SAndroid Build Coastguard Worker return omit_binary_values_;
200*635a8641SAndroid Build Coastguard Worker }
201*635a8641SAndroid Build Coastguard Worker NOTREACHED();
202*635a8641SAndroid Build Coastguard Worker return false;
203*635a8641SAndroid Build Coastguard Worker }
204*635a8641SAndroid Build Coastguard Worker
IndentLine(size_t depth)205*635a8641SAndroid Build Coastguard Worker void JSONWriter::IndentLine(size_t depth) {
206*635a8641SAndroid Build Coastguard Worker json_string_->append(depth * 3U, ' ');
207*635a8641SAndroid Build Coastguard Worker }
208*635a8641SAndroid Build Coastguard Worker
209*635a8641SAndroid Build Coastguard Worker } // namespace base
210