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.
5 #include "base/json/json_writer.h"
9 #include "base/json/string_escape.h"
10 #include "base/logging.h"
11 #include "base/stringprintf.h"
12 #include "base/string_number_conversions.h"
13 #include "base/values.h"
14 #include "base/utf_string_conversions.h"
19 static const char kPrettyPrintLineEnding
[] = "\r\n";
21 static const char kPrettyPrintLineEnding
[] = "\n";
25 const char* JSONWriter::kEmptyArray
= "[]";
28 void JSONWriter::Write(const Value
* const node
, std::string
* json
) {
29 WriteWithOptions(node
, 0, json
);
33 void JSONWriter::WriteWithOptions(const Value
* const node
, int options
,
36 // Is there a better way to estimate the size of the output?
39 bool escape
= !(options
& OPTIONS_DO_NOT_ESCAPE
);
40 bool omit_binary_values
= !!(options
& OPTIONS_OMIT_BINARY_VALUES
);
41 bool omit_double_type_preservation
=
42 !!(options
& OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION
);
43 bool pretty_print
= !!(options
& OPTIONS_PRETTY_PRINT
);
45 JSONWriter
writer(escape
, omit_binary_values
, omit_double_type_preservation
,
47 writer
.BuildJSONString(node
, 0);
50 json
->append(kPrettyPrintLineEnding
);
53 JSONWriter::JSONWriter(bool escape
, bool omit_binary_values
,
54 bool omit_double_type_preservation
, bool pretty_print
,
57 omit_binary_values_(omit_binary_values
),
58 omit_double_type_preservation_(omit_double_type_preservation
),
59 pretty_print_(pretty_print
),
64 void JSONWriter::BuildJSONString(const Value
* const node
, int depth
) {
65 switch (node
->GetType()) {
66 case Value::TYPE_NULL
:
67 json_string_
->append("null");
70 case Value::TYPE_BOOLEAN
:
73 bool result
= node
->GetAsBoolean(&value
);
75 json_string_
->append(value
? "true" : "false");
79 case Value::TYPE_INTEGER
:
82 bool result
= node
->GetAsInteger(&value
);
84 base::StringAppendF(json_string_
, "%d", value
);
88 case Value::TYPE_DOUBLE
:
91 bool result
= node
->GetAsDouble(&value
);
93 if (omit_double_type_preservation_
&&
96 std::floor(value
) == value
) {
97 json_string_
->append(Int64ToString(static_cast<int64
>(value
)));
100 std::string real
= DoubleToString(value
);
101 // Ensure that the number has a .0 if there's no decimal or 'e'. This
102 // makes sure that when we read the JSON back, it's interpreted as a
103 // real rather than an int.
104 if (real
.find('.') == std::string::npos
&&
105 real
.find('e') == std::string::npos
&&
106 real
.find('E') == std::string::npos
) {
109 // The JSON spec requires that non-integer values in the range (-1,1)
110 // have a zero before the decimal point - ".52" is not valid, "0.52" is.
111 if (real
[0] == '.') {
113 } else if (real
.length() > 1 && real
[0] == '-' && real
[1] == '.') {
114 // "-.1" bad "-0.1" good
117 json_string_
->append(real
);
121 case Value::TYPE_STRING
:
124 bool result
= node
->GetAsString(&value
);
127 JsonDoubleQuote(UTF8ToUTF16(value
), true, json_string_
);
129 JsonDoubleQuote(value
, true, json_string_
);
134 case Value::TYPE_LIST
:
136 json_string_
->append("[");
138 json_string_
->append(" ");
140 const ListValue
* list
= static_cast<const ListValue
*>(node
);
141 for (size_t i
= 0; i
< list
->GetSize(); ++i
) {
142 const Value
* value
= NULL
;
143 bool result
= list
->Get(i
, &value
);
146 if (omit_binary_values_
&& value
->GetType() == Value::TYPE_BINARY
) {
151 json_string_
->append(",");
153 json_string_
->append(" ");
156 BuildJSONString(value
, depth
);
160 json_string_
->append(" ");
161 json_string_
->append("]");
165 case Value::TYPE_DICTIONARY
:
167 json_string_
->append("{");
169 json_string_
->append(kPrettyPrintLineEnding
);
171 const DictionaryValue
* dict
=
172 static_cast<const DictionaryValue
*>(node
);
173 for (DictionaryValue::key_iterator key_itr
= dict
->begin_keys();
174 key_itr
!= dict
->end_keys();
176 const Value
* value
= NULL
;
177 bool result
= dict
->GetWithoutPathExpansion(*key_itr
, &value
);
180 if (omit_binary_values_
&& value
->GetType() == Value::TYPE_BINARY
) {
184 if (key_itr
!= dict
->begin_keys()) {
185 json_string_
->append(",");
187 json_string_
->append(kPrettyPrintLineEnding
);
191 IndentLine(depth
+ 1);
192 AppendQuotedString(*key_itr
);
194 json_string_
->append(": ");
196 json_string_
->append(":");
198 BuildJSONString(value
, depth
+ 1);
202 json_string_
->append(kPrettyPrintLineEnding
);
204 json_string_
->append("}");
206 json_string_
->append("}");
211 case Value::TYPE_BINARY
:
213 if (!omit_binary_values_
) {
214 NOTREACHED() << "Cannot serialize binary value.";
220 NOTREACHED() << "unknown json type";
224 void JSONWriter::AppendQuotedString(const std::string
& str
) {
225 // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we
226 // have to convert it to UTF-16. This round-trip is suboptimal.
227 JsonDoubleQuote(UTF8ToUTF16(str
), true, json_string_
);
230 void JSONWriter::IndentLine(int depth
) {
231 // It may be faster to keep an indent string so we don't have to keep
233 json_string_
->append(std::string(depth
* 3, ' '));