OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/json/json_writer.h" | 5 #include "base/json/json_writer.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 | 8 |
9 #include "base/json/string_escape.h" | 9 #include "base/json/string_escape.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/stringprintf.h" | 11 #include "base/stringprintf.h" |
12 #include "base/string_number_conversions.h" | 12 #include "base/string_number_conversions.h" |
13 #include "base/values.h" | 13 #include "base/values.h" |
14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
15 | 15 |
16 namespace base { | 16 namespace base { |
17 | 17 |
18 #if defined(OS_WIN) | 18 #if defined(OS_WIN) |
19 static const char kPrettyPrintLineEnding[] = "\r\n"; | 19 static const char kPrettyPrintLineEnding[] = "\r\n"; |
20 #else | 20 #else |
21 static const char kPrettyPrintLineEnding[] = "\n"; | 21 static const char kPrettyPrintLineEnding[] = "\n"; |
22 #endif | 22 #endif |
23 | 23 |
24 /* static */ | 24 /* static */ |
25 const char* JSONWriter::kEmptyArray = "[]"; | 25 const char* JSONWriter::kEmptyArray = "[]"; |
26 | 26 |
27 /* static */ | 27 /* static */ |
28 void JSONWriter::Write(const Value* const node, | 28 void JSONWriter::Write(const Value* const node, std::string* json) { |
29 bool pretty_print, | 29 WriteWithOptions(node, 0, json); |
30 std::string* json) { | |
31 WriteWithOptions(node, pretty_print, 0, json); | |
32 } | 30 } |
33 | 31 |
34 /* static */ | 32 /* static */ |
35 void JSONWriter::WriteWithOptions(const Value* const node, | 33 void JSONWriter::WriteWithOptions(const Value* const node, int options, |
36 bool pretty_print, | |
37 int options, | |
38 std::string* json) { | 34 std::string* json) { |
39 json->clear(); | 35 json->clear(); |
40 // Is there a better way to estimate the size of the output? | 36 // Is there a better way to estimate the size of the output? |
41 json->reserve(1024); | 37 json->reserve(1024); |
42 JSONWriter writer(pretty_print, json); | 38 |
43 bool escape = !(options & OPTIONS_DO_NOT_ESCAPE); | 39 bool escape = !(options & OPTIONS_DO_NOT_ESCAPE); |
44 bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES); | 40 bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES); |
45 bool omit_double_type_preservation = | 41 bool omit_double_type_preservation = |
46 !!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION); | 42 !!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION); |
47 writer.BuildJSONString(node, 0, escape, omit_binary_values, | 43 bool pretty_print = !!(options & OPTIONS_PRETTY_PRINT); |
48 omit_double_type_preservation); | 44 |
| 45 JSONWriter writer(escape, omit_binary_values, omit_double_type_preservation, |
| 46 pretty_print, json); |
| 47 writer.BuildJSONString(node, 0); |
| 48 |
49 if (pretty_print) | 49 if (pretty_print) |
50 json->append(kPrettyPrintLineEnding); | 50 json->append(kPrettyPrintLineEnding); |
51 } | 51 } |
52 | 52 |
53 JSONWriter::JSONWriter(bool pretty_print, std::string* json) | 53 JSONWriter::JSONWriter(bool escape, bool omit_binary_values, |
54 : json_string_(json), | 54 bool omit_double_type_preservation, bool pretty_print, |
55 pretty_print_(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) { |
56 DCHECK(json); | 61 DCHECK(json); |
57 } | 62 } |
58 | 63 |
59 void JSONWriter::BuildJSONString(const Value* const node, | 64 void JSONWriter::BuildJSONString(const Value* const node, int depth) { |
60 int depth, | |
61 bool escape, | |
62 bool omit_binary_values, | |
63 bool omit_double_type_preservation) { | |
64 switch (node->GetType()) { | 65 switch (node->GetType()) { |
65 case Value::TYPE_NULL: | 66 case Value::TYPE_NULL: |
66 json_string_->append("null"); | 67 json_string_->append("null"); |
67 break; | 68 break; |
68 | 69 |
69 case Value::TYPE_BOOLEAN: | 70 case Value::TYPE_BOOLEAN: |
70 { | 71 { |
71 bool value; | 72 bool value; |
72 bool result = node->GetAsBoolean(&value); | 73 bool result = node->GetAsBoolean(&value); |
73 DCHECK(result); | 74 DCHECK(result); |
74 json_string_->append(value ? "true" : "false"); | 75 json_string_->append(value ? "true" : "false"); |
75 break; | 76 break; |
76 } | 77 } |
77 | 78 |
78 case Value::TYPE_INTEGER: | 79 case Value::TYPE_INTEGER: |
79 { | 80 { |
80 int value; | 81 int value; |
81 bool result = node->GetAsInteger(&value); | 82 bool result = node->GetAsInteger(&value); |
82 DCHECK(result); | 83 DCHECK(result); |
83 base::StringAppendF(json_string_, "%d", value); | 84 base::StringAppendF(json_string_, "%d", value); |
84 break; | 85 break; |
85 } | 86 } |
86 | 87 |
87 case Value::TYPE_DOUBLE: | 88 case Value::TYPE_DOUBLE: |
88 { | 89 { |
89 double value; | 90 double value; |
90 bool result = node->GetAsDouble(&value); | 91 bool result = node->GetAsDouble(&value); |
91 DCHECK(result); | 92 DCHECK(result); |
92 if (omit_double_type_preservation && | 93 if (omit_double_type_preservation_ && |
93 value <= kint64max && | 94 value <= kint64max && |
94 value >= kint64min && | 95 value >= kint64min && |
95 std::floor(value) == value) { | 96 std::floor(value) == value) { |
96 json_string_->append(Int64ToString(static_cast<int64>(value))); | 97 json_string_->append(Int64ToString(static_cast<int64>(value))); |
97 break; | 98 break; |
98 } | 99 } |
99 std::string real = DoubleToString(value); | 100 std::string real = DoubleToString(value); |
100 // Ensure that the number has a .0 if there's no decimal or 'e'. This | 101 // Ensure that the number has a .0 if there's no decimal or 'e'. This |
101 // makes sure that when we read the JSON back, it's interpreted as a | 102 // makes sure that when we read the JSON back, it's interpreted as a |
102 // real rather than an int. | 103 // real rather than an int. |
(...skipping 12 matching lines...) Expand all Loading... |
115 } | 116 } |
116 json_string_->append(real); | 117 json_string_->append(real); |
117 break; | 118 break; |
118 } | 119 } |
119 | 120 |
120 case Value::TYPE_STRING: | 121 case Value::TYPE_STRING: |
121 { | 122 { |
122 std::string value; | 123 std::string value; |
123 bool result = node->GetAsString(&value); | 124 bool result = node->GetAsString(&value); |
124 DCHECK(result); | 125 DCHECK(result); |
125 if (escape) { | 126 if (escape_) { |
126 JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_); | 127 JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_); |
127 } else { | 128 } else { |
128 JsonDoubleQuote(value, true, json_string_); | 129 JsonDoubleQuote(value, true, json_string_); |
129 } | 130 } |
130 break; | 131 break; |
131 } | 132 } |
132 | 133 |
133 case Value::TYPE_LIST: | 134 case Value::TYPE_LIST: |
134 { | 135 { |
135 json_string_->append("["); | 136 json_string_->append("["); |
136 if (pretty_print_) | 137 if (pretty_print_) |
137 json_string_->append(" "); | 138 json_string_->append(" "); |
138 | 139 |
139 const ListValue* list = static_cast<const ListValue*>(node); | 140 const ListValue* list = static_cast<const ListValue*>(node); |
140 for (size_t i = 0; i < list->GetSize(); ++i) { | 141 for (size_t i = 0; i < list->GetSize(); ++i) { |
141 Value* value = NULL; | 142 Value* value = NULL; |
142 bool result = list->Get(i, &value); | 143 bool result = list->Get(i, &value); |
143 DCHECK(result); | 144 DCHECK(result); |
144 | 145 |
145 if (omit_binary_values && value->GetType() == Value::TYPE_BINARY) { | 146 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) { |
146 continue; | 147 continue; |
147 } | 148 } |
148 | 149 |
149 if (i != 0) { | 150 if (i != 0) { |
150 json_string_->append(","); | 151 json_string_->append(","); |
151 if (pretty_print_) | 152 if (pretty_print_) |
152 json_string_->append(" "); | 153 json_string_->append(" "); |
153 } | 154 } |
154 | 155 |
155 BuildJSONString(value, depth, escape, omit_binary_values, | 156 BuildJSONString(value, depth); |
156 omit_double_type_preservation); | |
157 } | 157 } |
158 | 158 |
159 if (pretty_print_) | 159 if (pretty_print_) |
160 json_string_->append(" "); | 160 json_string_->append(" "); |
161 json_string_->append("]"); | 161 json_string_->append("]"); |
162 break; | 162 break; |
163 } | 163 } |
164 | 164 |
165 case Value::TYPE_DICTIONARY: | 165 case Value::TYPE_DICTIONARY: |
166 { | 166 { |
167 json_string_->append("{"); | 167 json_string_->append("{"); |
168 if (pretty_print_) | 168 if (pretty_print_) |
169 json_string_->append(kPrettyPrintLineEnding); | 169 json_string_->append(kPrettyPrintLineEnding); |
170 | 170 |
171 const DictionaryValue* dict = | 171 const DictionaryValue* dict = |
172 static_cast<const DictionaryValue*>(node); | 172 static_cast<const DictionaryValue*>(node); |
173 for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); | 173 for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); |
174 key_itr != dict->end_keys(); | 174 key_itr != dict->end_keys(); |
175 ++key_itr) { | 175 ++key_itr) { |
176 Value* value = NULL; | 176 Value* value = NULL; |
177 bool result = dict->GetWithoutPathExpansion(*key_itr, &value); | 177 bool result = dict->GetWithoutPathExpansion(*key_itr, &value); |
178 DCHECK(result); | 178 DCHECK(result); |
179 | 179 |
180 if (omit_binary_values && value->GetType() == Value::TYPE_BINARY) { | 180 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) { |
181 continue; | 181 continue; |
182 } | 182 } |
183 | 183 |
184 if (key_itr != dict->begin_keys()) { | 184 if (key_itr != dict->begin_keys()) { |
185 json_string_->append(","); | 185 json_string_->append(","); |
186 if (pretty_print_) | 186 if (pretty_print_) |
187 json_string_->append(kPrettyPrintLineEnding); | 187 json_string_->append(kPrettyPrintLineEnding); |
188 } | 188 } |
189 | 189 |
190 if (pretty_print_) | 190 if (pretty_print_) |
191 IndentLine(depth + 1); | 191 IndentLine(depth + 1); |
192 AppendQuotedString(*key_itr); | 192 AppendQuotedString(*key_itr); |
193 if (pretty_print_) { | 193 if (pretty_print_) { |
194 json_string_->append(": "); | 194 json_string_->append(": "); |
195 } else { | 195 } else { |
196 json_string_->append(":"); | 196 json_string_->append(":"); |
197 } | 197 } |
198 BuildJSONString(value, depth + 1, escape, omit_binary_values, | 198 BuildJSONString(value, depth + 1); |
199 omit_double_type_preservation); | |
200 } | 199 } |
201 | 200 |
202 if (pretty_print_) { | 201 if (pretty_print_) { |
203 json_string_->append(kPrettyPrintLineEnding); | 202 json_string_->append(kPrettyPrintLineEnding); |
204 IndentLine(depth); | 203 IndentLine(depth); |
205 json_string_->append("}"); | 204 json_string_->append("}"); |
206 } else { | 205 } else { |
207 json_string_->append("}"); | 206 json_string_->append("}"); |
208 } | 207 } |
209 break; | 208 break; |
210 } | 209 } |
211 | 210 |
212 case Value::TYPE_BINARY: | 211 case Value::TYPE_BINARY: |
213 { | 212 { |
214 if (!omit_binary_values) { | 213 if (!omit_binary_values_) { |
215 NOTREACHED() << "Cannot serialize binary value."; | 214 NOTREACHED() << "Cannot serialize binary value."; |
216 } | 215 } |
217 break; | 216 break; |
218 } | 217 } |
219 | 218 |
220 default: | 219 default: |
221 NOTREACHED() << "unknown json type"; | 220 NOTREACHED() << "unknown json type"; |
222 } | 221 } |
223 } | 222 } |
224 | 223 |
225 void JSONWriter::AppendQuotedString(const std::string& str) { | 224 void JSONWriter::AppendQuotedString(const std::string& str) { |
226 // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we | 225 // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we |
227 // have to convert it to UTF-16. This round-trip is suboptimal. | 226 // have to convert it to UTF-16. This round-trip is suboptimal. |
228 JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_); | 227 JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_); |
229 } | 228 } |
230 | 229 |
231 void JSONWriter::IndentLine(int depth) { | 230 void JSONWriter::IndentLine(int depth) { |
232 // It may be faster to keep an indent string so we don't have to keep | 231 // It may be faster to keep an indent string so we don't have to keep |
233 // reallocating. | 232 // reallocating. |
234 json_string_->append(std::string(depth * 3, ' ')); | 233 json_string_->append(std::string(depth * 3, ' ')); |
235 } | 234 } |
236 | 235 |
237 } // namespace base | 236 } // namespace base |
OLD | NEW |