Update .DEPS.git
[chromium-blink-merge.git] / base / json / json_writer.cc
blobe8cf9ac861b606fcc1e0e4985a590c180459d112
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"
7 #include <cmath>
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"
16 namespace base {
18 #if defined(OS_WIN)
19 static const char kPrettyPrintLineEnding[] = "\r\n";
20 #else
21 static const char kPrettyPrintLineEnding[] = "\n";
22 #endif
24 /* static */
25 const char* JSONWriter::kEmptyArray = "[]";
27 /* static */
28 void JSONWriter::Write(const Value* const node, std::string* json) {
29 WriteWithOptions(node, 0, json);
32 /* static */
33 void JSONWriter::WriteWithOptions(const Value* const node, int options,
34 std::string* json) {
35 json->clear();
36 // Is there a better way to estimate the size of the output?
37 json->reserve(1024);
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,
46 pretty_print, json);
47 writer.BuildJSONString(node, 0);
49 if (pretty_print)
50 json->append(kPrettyPrintLineEnding);
53 JSONWriter::JSONWriter(bool escape, bool omit_binary_values,
54 bool omit_double_type_preservation, bool pretty_print,
55 std::string* json)
56 : escape_(escape),
57 omit_binary_values_(omit_binary_values),
58 omit_double_type_preservation_(omit_double_type_preservation),
59 pretty_print_(pretty_print),
60 json_string_(json) {
61 DCHECK(json);
64 void JSONWriter::BuildJSONString(const Value* const node, int depth) {
65 switch (node->GetType()) {
66 case Value::TYPE_NULL:
67 json_string_->append("null");
68 break;
70 case Value::TYPE_BOOLEAN:
72 bool value;
73 bool result = node->GetAsBoolean(&value);
74 DCHECK(result);
75 json_string_->append(value ? "true" : "false");
76 break;
79 case Value::TYPE_INTEGER:
81 int value;
82 bool result = node->GetAsInteger(&value);
83 DCHECK(result);
84 base::StringAppendF(json_string_, "%d", value);
85 break;
88 case Value::TYPE_DOUBLE:
90 double value;
91 bool result = node->GetAsDouble(&value);
92 DCHECK(result);
93 if (omit_double_type_preservation_ &&
94 value <= kint64max &&
95 value >= kint64min &&
96 std::floor(value) == value) {
97 json_string_->append(Int64ToString(static_cast<int64>(value)));
98 break;
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) {
107 real.append(".0");
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] == '.') {
112 real.insert(0, "0");
113 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
114 // "-.1" bad "-0.1" good
115 real.insert(1, "0");
117 json_string_->append(real);
118 break;
121 case Value::TYPE_STRING:
123 std::string value;
124 bool result = node->GetAsString(&value);
125 DCHECK(result);
126 if (escape_) {
127 JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_);
128 } else {
129 JsonDoubleQuote(value, true, json_string_);
131 break;
134 case Value::TYPE_LIST:
136 json_string_->append("[");
137 if (pretty_print_)
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);
144 DCHECK(result);
146 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) {
147 continue;
150 if (i != 0) {
151 json_string_->append(",");
152 if (pretty_print_)
153 json_string_->append(" ");
156 BuildJSONString(value, depth);
159 if (pretty_print_)
160 json_string_->append(" ");
161 json_string_->append("]");
162 break;
165 case Value::TYPE_DICTIONARY:
167 json_string_->append("{");
168 if (pretty_print_)
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();
175 ++key_itr) {
176 const Value* value = NULL;
177 bool result = dict->GetWithoutPathExpansion(*key_itr, &value);
178 DCHECK(result);
180 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) {
181 continue;
184 if (key_itr != dict->begin_keys()) {
185 json_string_->append(",");
186 if (pretty_print_)
187 json_string_->append(kPrettyPrintLineEnding);
190 if (pretty_print_)
191 IndentLine(depth + 1);
192 AppendQuotedString(*key_itr);
193 if (pretty_print_) {
194 json_string_->append(": ");
195 } else {
196 json_string_->append(":");
198 BuildJSONString(value, depth + 1);
201 if (pretty_print_) {
202 json_string_->append(kPrettyPrintLineEnding);
203 IndentLine(depth);
204 json_string_->append("}");
205 } else {
206 json_string_->append("}");
208 break;
211 case Value::TYPE_BINARY:
213 if (!omit_binary_values_) {
214 NOTREACHED() << "Cannot serialize binary value.";
216 break;
219 default:
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
232 // reallocating.
233 json_string_->append(std::string(depth * 3, ' '));
236 } // namespace base