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

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

Issue 1120006: detect preferences errors (Closed)
Patch Set: changes from review Created 10 years, 8 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
« no previous file with comments | « base/json/json_reader.h ('k') | base/json/json_reader_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) 2009 The Chromium Authors. All rights reserved. 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 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_reader.h" 5 #include "base/json/json_reader.h"
6 6
7 #include "base/float_util.h" 7 #include "base/float_util.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/scoped_ptr.h" 9 #include "base/scoped_ptr.h"
10 #include "base/string_util.h" 10 #include "base/string_util.h"
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 const char* JSONReader::kUnexpectedDataAfterRoot = 88 const char* JSONReader::kUnexpectedDataAfterRoot =
89 "Unexpected data after root element."; 89 "Unexpected data after root element.";
90 const char* JSONReader::kUnsupportedEncoding = 90 const char* JSONReader::kUnsupportedEncoding =
91 "Unsupported encoding. JSON must be UTF-8."; 91 "Unsupported encoding. JSON must be UTF-8.";
92 const char* JSONReader::kUnquotedDictionaryKey = 92 const char* JSONReader::kUnquotedDictionaryKey =
93 "Dictionary keys must be quoted."; 93 "Dictionary keys must be quoted.";
94 94
95 /* static */ 95 /* static */
96 Value* JSONReader::Read(const std::string& json, 96 Value* JSONReader::Read(const std::string& json,
97 bool allow_trailing_comma) { 97 bool allow_trailing_comma) {
98 return ReadAndReturnError(json, allow_trailing_comma, NULL); 98 return ReadAndReturnError(json, allow_trailing_comma, NULL, NULL);
99 } 99 }
100 100
101 /* static */ 101 /* static */
102 Value* JSONReader::ReadAndReturnError(const std::string& json, 102 Value* JSONReader::ReadAndReturnError(const std::string& json,
103 bool allow_trailing_comma, 103 bool allow_trailing_comma,
104 std::string *error_message_out) { 104 int* error_code_out,
105 std::string* error_msg_out) {
105 JSONReader reader = JSONReader(); 106 JSONReader reader = JSONReader();
106 Value* root = reader.JsonToValue(json, true, allow_trailing_comma); 107 Value* root = reader.JsonToValue(json, true, allow_trailing_comma);
107 if (root) 108 if (root)
108 return root; 109 return root;
109 110
110 if (error_message_out) 111 if (error_code_out)
111 *error_message_out = reader.error_message(); 112 *error_code_out = reader.error_code();
113 if (error_msg_out)
114 *error_msg_out = reader.GetErrorMessage();
112 115
113 return NULL; 116 return NULL;
114 } 117 }
115 118
116 /* static */ 119 /* static */
117 std::string JSONReader::FormatErrorMessage(int line, int column, 120 std::string JSONReader::FormatErrorMessage(int line, int column,
118 const char* description) { 121 const std::string& description) {
119 return StringPrintf("Line: %i, column: %i, %s", 122 if (line || column) {
120 line, column, description); 123 return StringPrintf("Line: %i, column: %i, %s",
124 line, column, description.c_str());
125 }
126 return description;
127 }
128
129 /* static */
130 std::string JSONReader::ErrorCodeToString(JsonParseError error_code) {
131 switch (error_code) {
132 case JSON_NO_ERROR:
133 return std::string();
134 case JSON_BAD_ROOT_ELEMENT_TYPE:
135 return kBadRootElementType;
136 case JSON_INVALID_ESCAPE:
137 return kInvalidEscape;
138 case JSON_SYNTAX_ERROR:
139 return kSyntaxError;
140 case JSON_TRAILING_COMMA:
141 return kTrailingComma;
142 case JSON_TOO_MUCH_NESTING:
143 return kTooMuchNesting;
144 case JSON_UNEXPECTED_DATA_AFTER_ROOT:
145 return kUnexpectedDataAfterRoot;
146 case JSON_UNSUPPORTED_ENCODING:
147 return kUnsupportedEncoding;
148 case JSON_UNQUOTED_DICTIONARY_KEY:
149 return kUnquotedDictionaryKey;
150 default:
151 NOTREACHED();
152 return std::string();
153 }
154 }
155
156 std::string JSONReader::GetErrorMessage() const {
157 return FormatErrorMessage(error_line_, error_col_,
158 ErrorCodeToString(error_code_));
121 } 159 }
122 160
123 JSONReader::JSONReader() 161 JSONReader::JSONReader()
124 : start_pos_(NULL), json_pos_(NULL), stack_depth_(0), 162 : start_pos_(NULL), json_pos_(NULL), stack_depth_(0),
125 allow_trailing_comma_(false) {} 163 allow_trailing_comma_(false),
164 error_code_(JSON_NO_ERROR), error_line_(0), error_col_(0) {}
126 165
127 Value* JSONReader::JsonToValue(const std::string& json, bool check_root, 166 Value* JSONReader::JsonToValue(const std::string& json, bool check_root,
128 bool allow_trailing_comma) { 167 bool allow_trailing_comma) {
129 // The input must be in UTF-8. 168 // The input must be in UTF-8.
130 if (!IsStringUTF8(json.c_str())) { 169 if (!IsStringUTF8(json.c_str())) {
131 error_message_ = kUnsupportedEncoding; 170 error_code_ = JSON_UNSUPPORTED_ENCODING;
132 return NULL; 171 return NULL;
133 } 172 }
134 173
135 // The conversion from UTF8 to wstring removes null bytes for us 174 // The conversion from UTF8 to wstring removes null bytes for us
136 // (a good thing). 175 // (a good thing).
137 std::wstring json_wide(UTF8ToWide(json)); 176 std::wstring json_wide(UTF8ToWide(json));
138 start_pos_ = json_wide.c_str(); 177 start_pos_ = json_wide.c_str();
139 178
140 // When the input JSON string starts with a UTF-8 Byte-Order-Mark 179 // When the input JSON string starts with a UTF-8 Byte-Order-Mark
141 // (0xEF, 0xBB, 0xBF), the UTF8ToWide() function converts it to a Unicode 180 // (0xEF, 0xBB, 0xBF), the UTF8ToWide() function converts it to a Unicode
142 // BOM (U+FEFF). To avoid the JSONReader::BuildValue() function from 181 // BOM (U+FEFF). To avoid the JSONReader::BuildValue() function from
143 // mis-treating a Unicode BOM as an invalid character and returning NULL, 182 // mis-treating a Unicode BOM as an invalid character and returning NULL,
144 // skip a converted Unicode BOM if it exists. 183 // skip a converted Unicode BOM if it exists.
145 if (!json_wide.empty() && start_pos_[0] == 0xFEFF) { 184 if (!json_wide.empty() && start_pos_[0] == 0xFEFF) {
146 ++start_pos_; 185 ++start_pos_;
147 } 186 }
148 187
149 json_pos_ = start_pos_; 188 json_pos_ = start_pos_;
150 allow_trailing_comma_ = allow_trailing_comma; 189 allow_trailing_comma_ = allow_trailing_comma;
151 stack_depth_ = 0; 190 stack_depth_ = 0;
152 error_message_.clear(); 191 error_code_ = JSON_NO_ERROR;
153 192
154 scoped_ptr<Value> root(BuildValue(check_root)); 193 scoped_ptr<Value> root(BuildValue(check_root));
155 if (root.get()) { 194 if (root.get()) {
156 if (ParseToken().type == Token::END_OF_INPUT) { 195 if (ParseToken().type == Token::END_OF_INPUT) {
157 return root.release(); 196 return root.release();
158 } else { 197 } else {
159 SetErrorMessage(kUnexpectedDataAfterRoot, json_pos_); 198 SetErrorCode(JSON_UNEXPECTED_DATA_AFTER_ROOT, json_pos_);
160 } 199 }
161 } 200 }
162 201
163 // Default to calling errors "syntax errors". 202 // Default to calling errors "syntax errors".
164 if (error_message_.empty()) 203 if (error_code_ == 0)
165 SetErrorMessage(kSyntaxError, json_pos_); 204 SetErrorCode(JSON_SYNTAX_ERROR, json_pos_);
166 205
167 return NULL; 206 return NULL;
168 } 207 }
169 208
170 Value* JSONReader::BuildValue(bool is_root) { 209 Value* JSONReader::BuildValue(bool is_root) {
171 ++stack_depth_; 210 ++stack_depth_;
172 if (stack_depth_ > kStackLimit) { 211 if (stack_depth_ > kStackLimit) {
173 SetErrorMessage(kTooMuchNesting, json_pos_); 212 SetErrorCode(JSON_TOO_MUCH_NESTING, json_pos_);
174 return NULL; 213 return NULL;
175 } 214 }
176 215
177 Token token = ParseToken(); 216 Token token = ParseToken();
178 // The root token must be an array or an object. 217 // The root token must be an array or an object.
179 if (is_root && token.type != Token::OBJECT_BEGIN && 218 if (is_root && token.type != Token::OBJECT_BEGIN &&
180 token.type != Token::ARRAY_BEGIN) { 219 token.type != Token::ARRAY_BEGIN) {
181 SetErrorMessage(kBadRootElementType, json_pos_); 220 SetErrorCode(JSON_BAD_ROOT_ELEMENT_TYPE, json_pos_);
182 return NULL; 221 return NULL;
183 } 222 }
184 223
185 scoped_ptr<Value> node; 224 scoped_ptr<Value> node;
186 225
187 switch (token.type) { 226 switch (token.type) {
188 case Token::END_OF_INPUT: 227 case Token::END_OF_INPUT:
189 case Token::INVALID_TOKEN: 228 case Token::INVALID_TOKEN:
190 return NULL; 229 return NULL;
191 230
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 266
228 // After a list value, we expect a comma or the end of the list. 267 // After a list value, we expect a comma or the end of the list.
229 token = ParseToken(); 268 token = ParseToken();
230 if (token.type == Token::LIST_SEPARATOR) { 269 if (token.type == Token::LIST_SEPARATOR) {
231 json_pos_ += token.length; 270 json_pos_ += token.length;
232 token = ParseToken(); 271 token = ParseToken();
233 // Trailing commas are invalid according to the JSON RFC, but some 272 // Trailing commas are invalid according to the JSON RFC, but some
234 // consumers need the parsing leniency, so handle accordingly. 273 // consumers need the parsing leniency, so handle accordingly.
235 if (token.type == Token::ARRAY_END) { 274 if (token.type == Token::ARRAY_END) {
236 if (!allow_trailing_comma_) { 275 if (!allow_trailing_comma_) {
237 SetErrorMessage(kTrailingComma, json_pos_); 276 SetErrorCode(JSON_TRAILING_COMMA, json_pos_);
238 return NULL; 277 return NULL;
239 } 278 }
240 // Trailing comma OK, stop parsing the Array. 279 // Trailing comma OK, stop parsing the Array.
241 break; 280 break;
242 } 281 }
243 } else if (token.type != Token::ARRAY_END) { 282 } else if (token.type != Token::ARRAY_END) {
244 // Unexpected value after list value. Bail out. 283 // Unexpected value after list value. Bail out.
245 return NULL; 284 return NULL;
246 } 285 }
247 } 286 }
248 if (token.type != Token::ARRAY_END) { 287 if (token.type != Token::ARRAY_END) {
249 return NULL; 288 return NULL;
250 } 289 }
251 break; 290 break;
252 } 291 }
253 292
254 case Token::OBJECT_BEGIN: 293 case Token::OBJECT_BEGIN:
255 { 294 {
256 json_pos_ += token.length; 295 json_pos_ += token.length;
257 token = ParseToken(); 296 token = ParseToken();
258 297
259 node.reset(new DictionaryValue); 298 node.reset(new DictionaryValue);
260 while (token.type != Token::OBJECT_END) { 299 while (token.type != Token::OBJECT_END) {
261 if (token.type != Token::STRING) { 300 if (token.type != Token::STRING) {
262 SetErrorMessage(kUnquotedDictionaryKey, json_pos_); 301 SetErrorCode(JSON_UNQUOTED_DICTIONARY_KEY, json_pos_);
263 return NULL; 302 return NULL;
264 } 303 }
265 scoped_ptr<Value> dict_key_value(DecodeString(token)); 304 scoped_ptr<Value> dict_key_value(DecodeString(token));
266 if (!dict_key_value.get()) 305 if (!dict_key_value.get())
267 return NULL; 306 return NULL;
268 307
269 // Convert the key into a wstring. 308 // Convert the key into a wstring.
270 std::wstring dict_key; 309 std::wstring dict_key;
271 bool success = dict_key_value->GetAsString(&dict_key); 310 bool success = dict_key_value->GetAsString(&dict_key);
272 DCHECK(success); 311 DCHECK(success);
(...skipping 14 matching lines...) Expand all
287 // After a key/value pair, we expect a comma or the end of the 326 // After a key/value pair, we expect a comma or the end of the
288 // object. 327 // object.
289 token = ParseToken(); 328 token = ParseToken();
290 if (token.type == Token::LIST_SEPARATOR) { 329 if (token.type == Token::LIST_SEPARATOR) {
291 json_pos_ += token.length; 330 json_pos_ += token.length;
292 token = ParseToken(); 331 token = ParseToken();
293 // Trailing commas are invalid according to the JSON RFC, but some 332 // Trailing commas are invalid according to the JSON RFC, but some
294 // consumers need the parsing leniency, so handle accordingly. 333 // consumers need the parsing leniency, so handle accordingly.
295 if (token.type == Token::OBJECT_END) { 334 if (token.type == Token::OBJECT_END) {
296 if (!allow_trailing_comma_) { 335 if (!allow_trailing_comma_) {
297 SetErrorMessage(kTrailingComma, json_pos_); 336 SetErrorCode(JSON_TRAILING_COMMA, json_pos_);
298 return NULL; 337 return NULL;
299 } 338 }
300 // Trailing comma OK, stop parsing the Object. 339 // Trailing comma OK, stop parsing the Object.
301 break; 340 break;
302 } 341 }
303 } else if (token.type != Token::OBJECT_END) { 342 } else if (token.type != Token::OBJECT_END) {
304 // Unexpected value after last object value. Bail out. 343 // Unexpected value after last object value. Bail out.
305 return NULL; 344 return NULL;
306 } 345 }
307 } 346 }
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 Token token(Token::STRING, json_pos_, 1); 416 Token token(Token::STRING, json_pos_, 1);
378 wchar_t c = token.NextChar(); 417 wchar_t c = token.NextChar();
379 while ('\0' != c) { 418 while ('\0' != c) {
380 if ('\\' == c) { 419 if ('\\' == c) {
381 ++token.length; 420 ++token.length;
382 c = token.NextChar(); 421 c = token.NextChar();
383 // Make sure the escaped char is valid. 422 // Make sure the escaped char is valid.
384 switch (c) { 423 switch (c) {
385 case 'x': 424 case 'x':
386 if (!ReadHexDigits(token, 2)) { 425 if (!ReadHexDigits(token, 2)) {
387 SetErrorMessage(kInvalidEscape, json_pos_ + token.length); 426 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length);
388 return kInvalidToken; 427 return kInvalidToken;
389 } 428 }
390 break; 429 break;
391 case 'u': 430 case 'u':
392 if (!ReadHexDigits(token, 4)) { 431 if (!ReadHexDigits(token, 4)) {
393 SetErrorMessage(kInvalidEscape, json_pos_ + token.length); 432 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length);
394 return kInvalidToken; 433 return kInvalidToken;
395 } 434 }
396 break; 435 break;
397 case '\\': 436 case '\\':
398 case '/': 437 case '/':
399 case 'b': 438 case 'b':
400 case 'f': 439 case 'f':
401 case 'n': 440 case 'n':
402 case 'r': 441 case 'r':
403 case 't': 442 case 't':
404 case 'v': 443 case 'v':
405 case '"': 444 case '"':
406 break; 445 break;
407 default: 446 default:
408 SetErrorMessage(kInvalidEscape, json_pos_ + token.length); 447 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length);
409 return kInvalidToken; 448 return kInvalidToken;
410 } 449 }
411 } else if ('"' == c) { 450 } else if ('"' == c) {
412 ++token.length; 451 ++token.length;
413 return token; 452 return token;
414 } 453 }
415 ++token.length; 454 ++token.length;
416 c = token.NextChar(); 455 c = token.NextChar();
417 } 456 }
418 return kInvalidToken; 457 return kInvalidToken;
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 return true; 649 return true;
611 } 650 }
612 ++json_pos_; 651 ++json_pos_;
613 } 652 }
614 } else { 653 } else {
615 return false; 654 return false;
616 } 655 }
617 return true; 656 return true;
618 } 657 }
619 658
620 void JSONReader::SetErrorMessage(const char* description, 659 void JSONReader::SetErrorCode(JsonParseError error,
621 const wchar_t* error_pos) { 660 const wchar_t* error_pos) {
622 int line_number = 1; 661 int line_number = 1;
623 int column_number = 1; 662 int column_number = 1;
624 663
625 // Figure out the line and column the error occured at. 664 // Figure out the line and column the error occured at.
626 for (const wchar_t* pos = start_pos_; pos != error_pos; ++pos) { 665 for (const wchar_t* pos = start_pos_; pos != error_pos; ++pos) {
627 if (*pos == '\0') { 666 if (*pos == '\0') {
628 NOTREACHED(); 667 NOTREACHED();
629 return; 668 return;
630 } 669 }
631 670
632 if (*pos == '\n') { 671 if (*pos == '\n') {
633 ++line_number; 672 ++line_number;
634 column_number = 1; 673 column_number = 1;
635 } else { 674 } else {
636 ++column_number; 675 ++column_number;
637 } 676 }
638 } 677 }
639 678
640 error_message_ = FormatErrorMessage(line_number, column_number, description); 679 error_line_ = line_number;
680 error_col_ = column_number;
681 error_code_ = error;
641 } 682 }
642 683
643 } // namespace base 684 } // namespace base
OLDNEW
« no previous file with comments | « base/json/json_reader.h ('k') | base/json/json_reader_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698