| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |