Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: base/json/json_writer.cc

Issue 130563010: Invalid JSON output when BinaryValue suppressed. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Produce same strings as before when error is returned for those who don't check em. Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/json/json_writer.h ('k') | base/json/json_writer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h" 13 #include "base/values.h"
14 14
15 namespace base { 15 namespace base {
16 16
17 #if defined(OS_WIN) 17 #if defined(OS_WIN)
18 const char kPrettyPrintLineEnding[] = "\r\n"; 18 const char kPrettyPrintLineEnding[] = "\r\n";
19 #else 19 #else
20 const char kPrettyPrintLineEnding[] = "\n"; 20 const char kPrettyPrintLineEnding[] = "\n";
21 #endif 21 #endif
22 22
23 // static 23 // static
24 void JSONWriter::Write(const Value* const node, std::string* json) { 24 bool JSONWriter::Write(const Value* const node, std::string* json) {
25 WriteWithOptions(node, 0, json); 25 return WriteWithOptions(node, 0, json);
26 } 26 }
27 27
28 // static 28 // static
29 void JSONWriter::WriteWithOptions(const Value* const node, int options, 29 bool JSONWriter::WriteWithOptions(const Value* const node, int options,
30 std::string* json) { 30 std::string* json) {
31 json->clear(); 31 json->clear();
32 // Is there a better way to estimate the size of the output? 32 // Is there a better way to estimate the size of the output?
33 json->reserve(1024); 33 json->reserve(1024);
34 34
35 JSONWriter writer(options, json); 35 JSONWriter writer(options, json);
36 writer.BuildJSONString(node, 0U); 36 bool result = writer.BuildJSONString(node, 0U);
37 37
38 if (options & OPTIONS_PRETTY_PRINT) 38 if (options & OPTIONS_PRETTY_PRINT)
39 json->append(kPrettyPrintLineEnding); 39 json->append(kPrettyPrintLineEnding);
40
41 return result;
40 } 42 }
41 43
42 JSONWriter::JSONWriter(int options, std::string* json) 44 JSONWriter::JSONWriter(int options, std::string* json)
43 : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0), 45 : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0),
44 omit_double_type_preservation_( 46 omit_double_type_preservation_(
45 (options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION) != 0), 47 (options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION) != 0),
46 pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0), 48 pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0),
47 json_string_(json) { 49 json_string_(json) {
48 DCHECK(json); 50 DCHECK(json);
49 } 51 }
50 52
51 void JSONWriter::BuildJSONString(const Value* const node, size_t depth) { 53 bool JSONWriter::BuildJSONString(const Value* const node, size_t depth) {
gab 2014/02/04 20:27:35 Why return a bool? It seems the only way this can
52 switch (node->GetType()) { 54 switch (node->GetType()) {
53 case Value::TYPE_NULL: 55 case Value::TYPE_NULL:
54 json_string_->append("null"); 56 json_string_->append("null");
55 break; 57 return true;
56 58
57 case Value::TYPE_BOOLEAN: 59 case Value::TYPE_BOOLEAN: {
gab 2014/02/04 20:27:35 I had also tried to fix the indent in my previous
58 { 60 bool value;
59 bool value; 61 bool result = node->GetAsBoolean(&value);
60 bool result = node->GetAsBoolean(&value); 62 DCHECK(result);
61 DCHECK(result); 63 json_string_->append(value ? "true" : "false");
62 json_string_->append(value ? "true" : "false"); 64 return result;
63 break; 65 }
66
67 case Value::TYPE_INTEGER: {
68 int value;
69 bool result = node->GetAsInteger(&value);
70 DCHECK(result);
71 json_string_->append(IntToString(value));
72 return result;
73 }
74
75 case Value::TYPE_DOUBLE: {
76 double value;
77 bool result = node->GetAsDouble(&value);
78 DCHECK(result);
79 if (omit_double_type_preservation_ &&
80 value <= kint64max &&
81 value >= kint64min &&
82 std::floor(value) == value) {
83 json_string_->append(Int64ToString(static_cast<int64>(value)));
84 return result;
85 }
86 std::string real = DoubleToString(value);
87 // Ensure that the number has a .0 if there's no decimal or 'e'. This
88 // makes sure that when we read the JSON back, it's interpreted as a
89 // real rather than an int.
90 if (real.find('.') == std::string::npos &&
91 real.find('e') == std::string::npos &&
92 real.find('E') == std::string::npos) {
93 real.append(".0");
94 }
95 // The JSON spec requires that non-integer values in the range (-1,1)
96 // have a zero before the decimal point - ".52" is not valid, "0.52" is.
97 if (real[0] == '.') {
98 real.insert(0U, 1U, '0');
99 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
100 // "-.1" bad "-0.1" good
101 real.insert(1U, 1U, '0');
102 }
103 json_string_->append(real);
104 return result;
105 }
106
107 case Value::TYPE_STRING: {
108 std::string value;
109 bool result = node->GetAsString(&value);
110 DCHECK(result);
111 EscapeJSONString(value, true, json_string_);
112 return result;
113 }
114
115 case Value::TYPE_LIST: {
116 json_string_->push_back('[');
117 if (pretty_print_)
118 json_string_->push_back(' ');
119
120 const ListValue* list;
121 bool first_value_output = false;
122 bool result = node->GetAsList(&list);
123 DCHECK(result);
124 for (ListValue::const_iterator it = list->begin(); it != list->end();
125 ++it) {
126 const Value* value = *it;
127 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY)
128 continue;
129
130 if (first_value_output) {
131 json_string_->push_back(',');
132 if (pretty_print_)
133 json_string_->push_back(' ');
134 }
135
136 if (!BuildJSONString(value, depth))
137 result = false;
138
139 first_value_output = true;
64 } 140 }
65 141
66 case Value::TYPE_INTEGER: 142 if (pretty_print_)
67 { 143 json_string_->push_back(' ');
68 int value; 144 json_string_->push_back(']');
69 bool result = node->GetAsInteger(&value); 145 return result;
70 DCHECK(result); 146 }
71 json_string_->append(IntToString(value));
72 break;
73 }
74 147
75 case Value::TYPE_DOUBLE: 148 case Value::TYPE_DICTIONARY: {
76 { 149 json_string_->push_back('{');
77 double value; 150 if (pretty_print_)
78 bool result = node->GetAsDouble(&value); 151 json_string_->append(kPrettyPrintLineEnding);
79 DCHECK(result); 152
80 if (omit_double_type_preservation_ && 153 const DictionaryValue* dict;
81 value <= kint64max && 154 bool first_value_output = false;
82 value >= kint64min && 155 bool result = node->GetAsDictionary(&dict);
83 std::floor(value) == value) { 156 DCHECK(result);
84 json_string_->append(Int64ToString(static_cast<int64>(value))); 157 for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
85 break; 158 itr.Advance()) {
159 if (omit_binary_values_ &&
160 itr.value().GetType() == Value::TYPE_BINARY) {
161 continue;
86 } 162 }
87 std::string real = DoubleToString(value); 163
88 // Ensure that the number has a .0 if there's no decimal or 'e'. This 164 if (first_value_output) {
89 // makes sure that when we read the JSON back, it's interpreted as a 165 json_string_->push_back(',');
90 // real rather than an int. 166 if (pretty_print_)
91 if (real.find('.') == std::string::npos && 167 json_string_->append(kPrettyPrintLineEnding);
92 real.find('e') == std::string::npos &&
93 real.find('E') == std::string::npos) {
94 real.append(".0");
95 } 168 }
96 // The JSON spec requires that non-integer values in the range (-1,1)
97 // have a zero before the decimal point - ".52" is not valid, "0.52" is.
98 if (real[0] == '.') {
99 real.insert(0U, 1U, '0');
100 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
101 // "-.1" bad "-0.1" good
102 real.insert(1U, 1U, '0');
103 }
104 json_string_->append(real);
105 break;
106 }
107 169
108 case Value::TYPE_STRING: 170 if (pretty_print_)
109 { 171 IndentLine(depth + 1U);
110 std::string value;
111 bool result = node->GetAsString(&value);
112 DCHECK(result);
113 EscapeJSONString(value, true, json_string_);
114 break;
115 }
116 172
117 case Value::TYPE_LIST: 173 EscapeJSONString(itr.key(), true, json_string_);
118 { 174 json_string_->push_back(':');
119 json_string_->push_back('[');
120 if (pretty_print_) 175 if (pretty_print_)
121 json_string_->push_back(' '); 176 json_string_->push_back(' ');
122 177
123 const ListValue* list = static_cast<const ListValue*>(node); 178 if (!BuildJSONString(&itr.value(), depth + 1U))
124 for (ListValue::const_iterator it = list->begin(); it != list->end(); 179 result = false;
125 ++it) {
126 const Value* value = *it;
127 180
128 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) 181 first_value_output = true;
129 continue;
130
131 if (it != list->begin()) {
132 json_string_->push_back(',');
133 if (pretty_print_)
134 json_string_->push_back(' ');
135 }
136
137 BuildJSONString(value, depth);
138 }
139
140 if (pretty_print_)
141 json_string_->push_back(' ');
142 json_string_->push_back(']');
143 break;
144 } 182 }
145 183
146 case Value::TYPE_DICTIONARY: 184 if (pretty_print_) {
147 { 185 json_string_->append(kPrettyPrintLineEnding);
148 json_string_->push_back('{'); 186 IndentLine(depth);
149 if (pretty_print_)
150 json_string_->append(kPrettyPrintLineEnding);
151
152 const DictionaryValue* dict =
153 static_cast<const DictionaryValue*>(node);
154 bool first_entry = true;
155 for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
156 itr.Advance(), first_entry = false) {
157 if (omit_binary_values_ &&
158 itr.value().GetType() == Value::TYPE_BINARY) {
159 continue;
160 }
161
162 if (!first_entry) {
163 json_string_->push_back(',');
164 if (pretty_print_)
165 json_string_->append(kPrettyPrintLineEnding);
166 }
167
168 if (pretty_print_)
169 IndentLine(depth + 1U);
170
171 EscapeJSONString(itr.key(), true, json_string_);
172
173 json_string_->push_back(':');
174 if (pretty_print_)
175 json_string_->push_back(' ');
176 BuildJSONString(&itr.value(), depth + 1U);
177 }
178
179 if (pretty_print_) {
180 json_string_->append(kPrettyPrintLineEnding);
181 IndentLine(depth);
182 json_string_->push_back('}');
183 } else {
184 json_string_->push_back('}');
185 }
186 break;
187 } 187 }
188 188
189 json_string_->push_back('}');
190 return result;
191 }
192
189 case Value::TYPE_BINARY: 193 case Value::TYPE_BINARY:
190 { 194 // Successful only if we're allowed to omit it.
191 if (!omit_binary_values_) { 195 return omit_binary_values_;
192 NOTREACHED() << "Cannot serialize binary value.";
193 }
194 break;
195 }
196 196
197 default: 197 default:
198 NOTREACHED() << "unknown json type"; 198 NOTREACHED() << "unknown json type";
199 return false;
199 } 200 }
200 } 201 }
201 202
202 void JSONWriter::IndentLine(size_t depth) { 203 void JSONWriter::IndentLine(size_t depth) {
203 json_string_->append(depth * 3U, ' '); 204 json_string_->append(depth * 3U, ' ');
204 } 205 }
205 206
206 } // namespace base 207 } // namespace base
OLDNEW
« no previous file with comments | « base/json/json_writer.h ('k') | base/json/json_writer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698