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

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: NOTREACHED() & return false at end of function. 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) {
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 59
58 case Value::TYPE_BOOLEAN: { 60 case Value::TYPE_BOOLEAN: {
59 bool value; 61 bool value;
60 bool result = node->GetAsBoolean(&value); 62 bool result = node->GetAsBoolean(&value);
61 DCHECK(result); 63 DCHECK(result);
62 json_string_->append(value ? "true" : "false"); 64 json_string_->append(value ? "true" : "false");
63 break; 65 return result;
64 } 66 }
65 67
66 case Value::TYPE_INTEGER: { 68 case Value::TYPE_INTEGER: {
67 int value; 69 int value;
68 bool result = node->GetAsInteger(&value); 70 bool result = node->GetAsInteger(&value);
69 DCHECK(result); 71 DCHECK(result);
70 json_string_->append(IntToString(value)); 72 json_string_->append(IntToString(value));
71 break; 73 return result;
72 } 74 }
73 75
74 case Value::TYPE_DOUBLE: { 76 case Value::TYPE_DOUBLE: {
75 double value; 77 double value;
76 bool result = node->GetAsDouble(&value); 78 bool result = node->GetAsDouble(&value);
77 DCHECK(result); 79 DCHECK(result);
78 if (omit_double_type_preservation_ && 80 if (omit_double_type_preservation_ &&
79 value <= kint64max && 81 value <= kint64max &&
80 value >= kint64min && 82 value >= kint64min &&
81 std::floor(value) == value) { 83 std::floor(value) == value) {
82 json_string_->append(Int64ToString(static_cast<int64>(value))); 84 json_string_->append(Int64ToString(static_cast<int64>(value)));
83 break; 85 return result;
84 } 86 }
85 std::string real = DoubleToString(value); 87 std::string real = DoubleToString(value);
86 // Ensure that the number has a .0 if there's no decimal or 'e'. This 88 // Ensure that the number has a .0 if there's no decimal or 'e'. This
87 // makes sure that when we read the JSON back, it's interpreted as a 89 // makes sure that when we read the JSON back, it's interpreted as a
88 // real rather than an int. 90 // real rather than an int.
89 if (real.find('.') == std::string::npos && 91 if (real.find('.') == std::string::npos &&
90 real.find('e') == std::string::npos && 92 real.find('e') == std::string::npos &&
91 real.find('E') == std::string::npos) { 93 real.find('E') == std::string::npos) {
92 real.append(".0"); 94 real.append(".0");
93 } 95 }
94 // The JSON spec requires that non-integer values in the range (-1,1) 96 // The JSON spec requires that non-integer values in the range (-1,1)
95 // have a zero before the decimal point - ".52" is not valid, "0.52" is. 97 // have a zero before the decimal point - ".52" is not valid, "0.52" is.
96 if (real[0] == '.') { 98 if (real[0] == '.') {
97 real.insert(0U, 1U, '0'); 99 real.insert(0U, 1U, '0');
98 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') { 100 } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
99 // "-.1" bad "-0.1" good 101 // "-.1" bad "-0.1" good
100 real.insert(1U, 1U, '0'); 102 real.insert(1U, 1U, '0');
101 } 103 }
102 json_string_->append(real); 104 json_string_->append(real);
103 break; 105 return result;
104 } 106 }
105 107
106 case Value::TYPE_STRING: { 108 case Value::TYPE_STRING: {
107 std::string value; 109 std::string value;
108 bool result = node->GetAsString(&value); 110 bool result = node->GetAsString(&value);
109 DCHECK(result); 111 DCHECK(result);
110 EscapeJSONString(value, true, json_string_); 112 EscapeJSONString(value, true, json_string_);
111 break; 113 return result;
112 } 114 }
113 115
114 case Value::TYPE_LIST: { 116 case Value::TYPE_LIST: {
115 json_string_->push_back('['); 117 json_string_->push_back('[');
116 if (pretty_print_) 118 if (pretty_print_)
117 json_string_->push_back(' '); 119 json_string_->push_back(' ');
118 120
119 const ListValue* list = static_cast<const ListValue*>(node); 121 const ListValue* list = NULL;
122 bool first_value_has_been_output = false;
123 bool result = node->GetAsList(&list);
124 DCHECK(result);
120 for (ListValue::const_iterator it = list->begin(); it != list->end(); 125 for (ListValue::const_iterator it = list->begin(); it != list->end();
121 ++it) { 126 ++it) {
122 const Value* value = *it; 127 const Value* value = *it;
123
124 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY) 128 if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY)
125 continue; 129 continue;
126 130
127 if (it != list->begin()) { 131 if (first_value_has_been_output) {
128 json_string_->push_back(','); 132 json_string_->push_back(',');
129 if (pretty_print_) 133 if (pretty_print_)
130 json_string_->push_back(' '); 134 json_string_->push_back(' ');
131 } 135 }
132 136
133 BuildJSONString(value, depth); 137 if (!BuildJSONString(value, depth))
138 result = false;
139
140 first_value_has_been_output = true;
134 } 141 }
135 142
136 if (pretty_print_) 143 if (pretty_print_)
137 json_string_->push_back(' '); 144 json_string_->push_back(' ');
138 json_string_->push_back(']'); 145 json_string_->push_back(']');
139 break; 146 return result;
140 } 147 }
141 148
142 case Value::TYPE_DICTIONARY: { 149 case Value::TYPE_DICTIONARY: {
143 json_string_->push_back('{'); 150 json_string_->push_back('{');
144 if (pretty_print_) 151 if (pretty_print_)
145 json_string_->append(kPrettyPrintLineEnding); 152 json_string_->append(kPrettyPrintLineEnding);
146 153
147 const DictionaryValue* dict = 154 const DictionaryValue* dict = NULL;
148 static_cast<const DictionaryValue*>(node); 155 bool first_value_has_been_output = false;
149 bool first_entry = true; 156 bool result = node->GetAsDictionary(&dict);
157 DCHECK(result);
150 for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd(); 158 for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
151 itr.Advance(), first_entry = false) { 159 itr.Advance()) {
152 if (omit_binary_values_ && 160 if (omit_binary_values_ &&
153 itr.value().GetType() == Value::TYPE_BINARY) { 161 itr.value().GetType() == Value::TYPE_BINARY) {
154 continue; 162 continue;
155 } 163 }
156 164
157 if (!first_entry) { 165 if (first_value_has_been_output) {
158 json_string_->push_back(','); 166 json_string_->push_back(',');
159 if (pretty_print_) 167 if (pretty_print_)
160 json_string_->append(kPrettyPrintLineEnding); 168 json_string_->append(kPrettyPrintLineEnding);
161 } 169 }
162 170
163 if (pretty_print_) 171 if (pretty_print_)
164 IndentLine(depth + 1U); 172 IndentLine(depth + 1U);
165 173
166 EscapeJSONString(itr.key(), true, json_string_); 174 EscapeJSONString(itr.key(), true, json_string_);
167
168 json_string_->push_back(':'); 175 json_string_->push_back(':');
169 if (pretty_print_) 176 if (pretty_print_)
170 json_string_->push_back(' '); 177 json_string_->push_back(' ');
171 BuildJSONString(&itr.value(), depth + 1U); 178
179 if (!BuildJSONString(&itr.value(), depth + 1U))
180 result = false;
181
182 first_value_has_been_output = true;
172 } 183 }
173 184
174 if (pretty_print_) { 185 if (pretty_print_) {
175 json_string_->append(kPrettyPrintLineEnding); 186 json_string_->append(kPrettyPrintLineEnding);
176 IndentLine(depth); 187 IndentLine(depth);
177 json_string_->push_back('}');
178 } else {
179 json_string_->push_back('}');
180 } 188 }
181 break; 189
190 json_string_->push_back('}');
191 return result;
182 } 192 }
183 193
184 case Value::TYPE_BINARY: { 194 case Value::TYPE_BINARY:
185 if (!omit_binary_values_) { 195 // Successful only if we're allowed to omit it.
186 NOTREACHED() << "Cannot serialize binary value."; 196 DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
187 } 197 return omit_binary_values_;
188 break;
189 }
190
191 default: {
192 NOTREACHED() << "unknown json type";
193 }
194 } 198 }
199 NOTREACHED();
200 return false;
195 } 201 }
196 202
197 void JSONWriter::IndentLine(size_t depth) { 203 void JSONWriter::IndentLine(size_t depth) {
198 json_string_->append(depth * 3U, ' '); 204 json_string_->append(depth * 3U, ' ');
199 } 205 }
200 206
201 } // 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