OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 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/json_writer.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/string_util.h" | |
9 #include "base/values.h" | |
10 #include "base/string_escape.h" | |
11 #include "base/utf_string_conversions.h" | |
12 | |
13 #if defined(OS_WIN) | |
14 static const char kPrettyPrintLineEnding[] = "\r\n"; | |
15 #else | |
16 static const char kPrettyPrintLineEnding[] = "\n"; | |
17 #endif | |
18 | |
19 /* static */ | |
20 void JSONWriter::Write(const Value* const node, | |
21 bool pretty_print, | |
22 std::string* json) { | |
23 WriteWithOptionalEscape(node, pretty_print, true, json); | |
24 } | |
25 | |
26 /* static */ | |
27 void JSONWriter::WriteWithOptionalEscape(const Value* const node, | |
28 bool pretty_print, | |
29 bool escape, | |
30 std::string* json) { | |
31 json->clear(); | |
32 // Is there a better way to estimate the size of the output? | |
33 json->reserve(1024); | |
34 JSONWriter writer(pretty_print, json); | |
35 writer.BuildJSONString(node, 0, escape); | |
36 if (pretty_print) | |
37 json->append(kPrettyPrintLineEnding); | |
38 } | |
39 | |
40 JSONWriter::JSONWriter(bool pretty_print, std::string* json) | |
41 : json_string_(json), | |
42 pretty_print_(pretty_print) { | |
43 DCHECK(json); | |
44 } | |
45 | |
46 void JSONWriter::BuildJSONString(const Value* const node, | |
47 int depth, | |
48 bool escape) { | |
49 switch(node->GetType()) { | |
50 case Value::TYPE_NULL: | |
51 json_string_->append("null"); | |
52 break; | |
53 | |
54 case Value::TYPE_BOOLEAN: | |
55 { | |
56 bool value; | |
57 bool result = node->GetAsBoolean(&value); | |
58 DCHECK(result); | |
59 json_string_->append(value ? "true" : "false"); | |
60 break; | |
61 } | |
62 | |
63 case Value::TYPE_INTEGER: | |
64 { | |
65 int value; | |
66 bool result = node->GetAsInteger(&value); | |
67 DCHECK(result); | |
68 StringAppendF(json_string_, "%d", value); | |
69 break; | |
70 } | |
71 | |
72 case Value::TYPE_REAL: | |
73 { | |
74 double value; | |
75 bool result = node->GetAsReal(&value); | |
76 DCHECK(result); | |
77 std::string real = DoubleToString(value); | |
78 // Ensure that the number has a .0 if there's no decimal or 'e'. This | |
79 // makes sure that when we read the JSON back, it's interpreted as a | |
80 // real rather than an int. | |
81 if (real.find('.') == std::string::npos && | |
82 real.find('e') == std::string::npos && | |
83 real.find('E') == std::string::npos) { | |
84 real.append(".0"); | |
85 } | |
86 // The JSON spec requires that non-integer values in the range (-1,1) | |
87 // have a zero before the decimal point - ".52" is not valid, "0.52" is. | |
88 if (real[0] == '.') { | |
89 real.insert(0, "0"); | |
90 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') { | |
91 // "-.1" bad "-0.1" good | |
92 real.insert(1, "0"); | |
93 } | |
94 json_string_->append(real); | |
95 break; | |
96 } | |
97 | |
98 case Value::TYPE_STRING: | |
99 { | |
100 std::string value; | |
101 bool result = node->GetAsString(&value); | |
102 DCHECK(result); | |
103 if (escape) { | |
104 string_escape::JsonDoubleQuote(UTF8ToUTF16(value), | |
105 true, | |
106 json_string_); | |
107 } else { | |
108 string_escape::JsonDoubleQuote(value, true, json_string_); | |
109 } | |
110 break; | |
111 } | |
112 | |
113 case Value::TYPE_LIST: | |
114 { | |
115 json_string_->append("["); | |
116 if (pretty_print_) | |
117 json_string_->append(" "); | |
118 | |
119 const ListValue* list = static_cast<const ListValue*>(node); | |
120 for (size_t i = 0; i < list->GetSize(); ++i) { | |
121 if (i != 0) { | |
122 json_string_->append(","); | |
123 if (pretty_print_) | |
124 json_string_->append(" "); | |
125 } | |
126 | |
127 Value* value = NULL; | |
128 bool result = list->Get(i, &value); | |
129 DCHECK(result); | |
130 BuildJSONString(value, depth, escape); | |
131 } | |
132 | |
133 if (pretty_print_) | |
134 json_string_->append(" "); | |
135 json_string_->append("]"); | |
136 break; | |
137 } | |
138 | |
139 case Value::TYPE_DICTIONARY: | |
140 { | |
141 json_string_->append("{"); | |
142 if (pretty_print_) | |
143 json_string_->append(kPrettyPrintLineEnding); | |
144 | |
145 const DictionaryValue* dict = | |
146 static_cast<const DictionaryValue*>(node); | |
147 for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); | |
148 key_itr != dict->end_keys(); | |
149 ++key_itr) { | |
150 | |
151 if (key_itr != dict->begin_keys()) { | |
152 json_string_->append(","); | |
153 if (pretty_print_) | |
154 json_string_->append(kPrettyPrintLineEnding); | |
155 } | |
156 | |
157 Value* value = NULL; | |
158 bool result = dict->Get(*key_itr, &value); | |
159 DCHECK(result); | |
160 | |
161 if (pretty_print_) | |
162 IndentLine(depth + 1); | |
163 AppendQuotedString(*key_itr); | |
164 if (pretty_print_) { | |
165 json_string_->append(": "); | |
166 } else { | |
167 json_string_->append(":"); | |
168 } | |
169 BuildJSONString(value, depth + 1, escape); | |
170 } | |
171 | |
172 if (pretty_print_) { | |
173 json_string_->append(kPrettyPrintLineEnding); | |
174 IndentLine(depth); | |
175 json_string_->append("}"); | |
176 } else { | |
177 json_string_->append("}"); | |
178 } | |
179 break; | |
180 } | |
181 | |
182 default: | |
183 // TODO(jhughes): handle TYPE_BINARY | |
184 NOTREACHED() << "unknown json type"; | |
185 } | |
186 } | |
187 | |
188 void JSONWriter::AppendQuotedString(const std::wstring& str) { | |
189 string_escape::JsonDoubleQuote(WideToUTF16Hack(str), | |
190 true, | |
191 json_string_); | |
192 } | |
193 | |
194 void JSONWriter::IndentLine(int depth) { | |
195 // It may be faster to keep an indent string so we don't have to keep | |
196 // reallocating. | |
197 json_string_->append(std::string(depth * 3, ' ')); | |
198 } | |
OLD | NEW |