Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
| 11 #include "base/string_number_conversions.h" | 11 #include "base/string_number_conversions.h" |
| 12 #include "base/string_piece.h" | |
| 12 #include "base/string_util.h" | 13 #include "base/string_util.h" |
| 14 #include "base/third_party/icu/icu_utf.h" | |
| 13 #include "base/utf_string_conversions.h" | 15 #include "base/utf_string_conversions.h" |
| 14 #include "base/values.h" | 16 #include "base/values.h" |
| 15 | 17 |
| 16 namespace { | 18 namespace { |
| 17 | 19 |
| 18 const wchar_t kNullString[] = L"null"; | 20 const char kNullString[] = "null"; |
| 19 const wchar_t kTrueString[] = L"true"; | 21 const char kTrueString[] = "true"; |
| 20 const wchar_t kFalseString[] = L"false"; | 22 const char kFalseString[] = "false"; |
| 21 | 23 |
| 22 const int kStackLimit = 100; | 24 const int kStackLimit = 100; |
| 23 | 25 |
| 24 // A helper method for ParseNumberToken. It reads an int from the end of | 26 // A helper method for ParseNumberToken. It reads an int from the end of |
| 25 // token. The method returns false if there is no valid integer at the end of | 27 // token. The method returns false if there is no valid integer at the end of |
| 26 // the token. | 28 // the token. |
| 27 bool ReadInt(base::JSONReader::Token& token, bool can_have_leading_zeros) { | 29 bool ReadInt(base::JSONReader::Token& token, bool can_have_leading_zeros) { |
| 28 wchar_t first = token.NextChar(); | 30 char first = token.NextChar(); |
| 29 int len = 0; | 31 int len = 0; |
| 30 | 32 |
| 31 // Read in more digits. | 33 // Read in more digits. |
| 32 wchar_t c = first; | 34 char c = first; |
| 33 while ('\0' != c && IsAsciiDigit(c)) { | 35 while ('\0' != c && IsAsciiDigit(c)) { |
| 34 ++token.length; | 36 ++token.length; |
| 35 ++len; | 37 ++len; |
| 36 c = token.NextChar(); | 38 c = token.NextChar(); |
| 37 } | 39 } |
| 38 // We need at least 1 digit. | 40 // We need at least 1 digit. |
| 39 if (len == 0) | 41 if (len == 0) |
| 40 return false; | 42 return false; |
| 41 | 43 |
| 42 if (!can_have_leading_zeros && len > 1 && '0' == first) | 44 if (!can_have_leading_zeros && len > 1 && '0' == first) |
| 43 return false; | 45 return false; |
| 44 | 46 |
| 45 return true; | 47 return true; |
| 46 } | 48 } |
| 47 | 49 |
| 48 // A helper method for ParseStringToken. It reads |digits| hex digits from the | 50 // A helper method for ParseStringToken. It reads |digits| hex digits from the |
| 49 // token. If the sequence if digits is not valid (contains other characters), | 51 // token. If the sequence if digits is not valid (contains other characters), |
| 50 // the method returns false. | 52 // the method returns false. |
| 51 bool ReadHexDigits(base::JSONReader::Token& token, int digits) { | 53 bool ReadHexDigits(base::JSONReader::Token& token, int digits) { |
| 52 for (int i = 1; i <= digits; ++i) { | 54 for (int i = 1; i <= digits; ++i) { |
| 53 wchar_t c = *(token.begin + token.length + i); | 55 char c = *(token.begin + token.length + i); |
| 54 if (c == '\0' || !IsHexDigit(c)) | 56 if (c == '\0' || !IsHexDigit(c)) |
| 55 return false; | 57 return false; |
| 56 } | 58 } |
| 57 | 59 |
| 58 token.length += digits; | 60 token.length += digits; |
| 59 return true; | 61 return true; |
| 60 } | 62 } |
| 61 | 63 |
| 62 } // namespace | 64 } // namespace |
| 63 | 65 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 76 const char* JSONReader::kUnexpectedDataAfterRoot = | 78 const char* JSONReader::kUnexpectedDataAfterRoot = |
| 77 "Unexpected data after root element."; | 79 "Unexpected data after root element."; |
| 78 const char* JSONReader::kUnsupportedEncoding = | 80 const char* JSONReader::kUnsupportedEncoding = |
| 79 "Unsupported encoding. JSON must be UTF-8."; | 81 "Unsupported encoding. JSON must be UTF-8."; |
| 80 const char* JSONReader::kUnquotedDictionaryKey = | 82 const char* JSONReader::kUnquotedDictionaryKey = |
| 81 "Dictionary keys must be quoted."; | 83 "Dictionary keys must be quoted."; |
| 82 | 84 |
| 83 JSONReader::JSONReader() | 85 JSONReader::JSONReader() |
| 84 : start_pos_(NULL), | 86 : start_pos_(NULL), |
| 85 json_pos_(NULL), | 87 json_pos_(NULL), |
| 88 end_pos_(NULL), | |
| 86 stack_depth_(0), | 89 stack_depth_(0), |
| 87 allow_trailing_comma_(false), | 90 allow_trailing_comma_(false), |
| 88 error_code_(JSON_NO_ERROR), | 91 error_code_(JSON_NO_ERROR), |
| 89 error_line_(0), | 92 error_line_(0), |
| 90 error_col_(0) {} | 93 error_col_(0) {} |
| 91 | 94 |
| 92 // static | 95 // static |
| 93 Value* JSONReader::Read(const std::string& json, | 96 Value* JSONReader::Read(const std::string& json, |
| 94 bool allow_trailing_comma) { | 97 bool allow_trailing_comma) { |
| 95 return ReadAndReturnError(json, allow_trailing_comma, NULL, NULL); | 98 return ReadAndReturnError(json, allow_trailing_comma, NULL, NULL); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 141 } | 144 } |
| 142 | 145 |
| 143 std::string JSONReader::GetErrorMessage() const { | 146 std::string JSONReader::GetErrorMessage() const { |
| 144 return FormatErrorMessage(error_line_, error_col_, | 147 return FormatErrorMessage(error_line_, error_col_, |
| 145 ErrorCodeToString(error_code_)); | 148 ErrorCodeToString(error_code_)); |
| 146 } | 149 } |
| 147 | 150 |
| 148 Value* JSONReader::JsonToValue(const std::string& json, bool check_root, | 151 Value* JSONReader::JsonToValue(const std::string& json, bool check_root, |
| 149 bool allow_trailing_comma) { | 152 bool allow_trailing_comma) { |
| 150 // The input must be in UTF-8. | 153 // The input must be in UTF-8. |
| 151 if (!IsStringUTF8(json.c_str())) { | 154 if (!IsStringUTF8(json.data())) { |
| 152 error_code_ = JSON_UNSUPPORTED_ENCODING; | 155 error_code_ = JSON_UNSUPPORTED_ENCODING; |
| 153 return NULL; | 156 return NULL; |
| 154 } | 157 } |
| 155 | 158 |
| 156 // The conversion from UTF8 to wstring removes null bytes for us | 159 start_pos_ = json.data(); |
| 157 // (a good thing). | 160 end_pos_ = start_pos_ + json.size(); |
| 158 std::wstring json_wide(UTF8ToWide(json)); | |
| 159 start_pos_ = json_wide.c_str(); | |
| 160 | 161 |
| 161 // When the input JSON string starts with a UTF-8 Byte-Order-Mark | 162 // When the input JSON string starts with a UTF-8 Byte-Order-Mark (U+FEFF) |
| 162 // (0xEF, 0xBB, 0xBF), the UTF8ToWide() function converts it to a Unicode | 163 // or <0xEF 0xBB 0xBF>, advance the start position to avoid the |
| 163 // BOM (U+FEFF). To avoid the JSONReader::BuildValue() function from | 164 // JSONReader::BuildValue() function from mis-treating a Unicode BOM as an |
| 164 // mis-treating a Unicode BOM as an invalid character and returning NULL, | 165 // invalid character and returning NULL. |
| 165 // skip a converted Unicode BOM if it exists. | 166 if (json.size() >= 3 && start_pos_[0] == 0xEF && |
| 166 if (!json_wide.empty() && start_pos_[0] == 0xFEFF) { | 167 start_pos_[1] == 0xBB && start_pos_[2] == 0xBF) { |
| 167 ++start_pos_; | 168 start_pos_ += 3; |
| 168 } | 169 } |
| 169 | 170 |
| 170 json_pos_ = start_pos_; | 171 json_pos_ = start_pos_; |
| 171 allow_trailing_comma_ = allow_trailing_comma; | 172 allow_trailing_comma_ = allow_trailing_comma; |
| 172 stack_depth_ = 0; | 173 stack_depth_ = 0; |
| 173 error_code_ = JSON_NO_ERROR; | 174 error_code_ = JSON_NO_ERROR; |
| 174 | 175 |
| 175 scoped_ptr<Value> root(BuildValue(check_root)); | 176 scoped_ptr<Value> root(BuildValue(check_root)); |
| 176 if (root.get()) { | 177 if (root.get()) { |
| 177 if (ParseToken().type == Token::END_OF_INPUT) { | 178 if (ParseToken().type == Token::END_OF_INPUT) { |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 349 json_pos_ += token.length; | 350 json_pos_ += token.length; |
| 350 | 351 |
| 351 --stack_depth_; | 352 --stack_depth_; |
| 352 return node.release(); | 353 return node.release(); |
| 353 } | 354 } |
| 354 | 355 |
| 355 JSONReader::Token JSONReader::ParseNumberToken() { | 356 JSONReader::Token JSONReader::ParseNumberToken() { |
| 356 // We just grab the number here. We validate the size in DecodeNumber. | 357 // We just grab the number here. We validate the size in DecodeNumber. |
| 357 // According to RFC4627, a valid number is: [minus] int [frac] [exp] | 358 // According to RFC4627, a valid number is: [minus] int [frac] [exp] |
| 358 Token token(Token::NUMBER, json_pos_, 0); | 359 Token token(Token::NUMBER, json_pos_, 0); |
| 359 wchar_t c = *json_pos_; | 360 char c = *json_pos_; |
| 360 if ('-' == c) { | 361 if ('-' == c) { |
| 361 ++token.length; | 362 ++token.length; |
| 362 c = token.NextChar(); | 363 c = token.NextChar(); |
| 363 } | 364 } |
| 364 | 365 |
| 365 if (!ReadInt(token, false)) | 366 if (!ReadInt(token, false)) |
| 366 return Token::CreateInvalidToken(); | 367 return Token::CreateInvalidToken(); |
| 367 | 368 |
| 368 // Optional fraction part | 369 // Optional fraction part |
| 369 c = token.NextChar(); | 370 c = token.NextChar(); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 383 c = token.NextChar(); | 384 c = token.NextChar(); |
| 384 } | 385 } |
| 385 if (!ReadInt(token, true)) | 386 if (!ReadInt(token, true)) |
| 386 return Token::CreateInvalidToken(); | 387 return Token::CreateInvalidToken(); |
| 387 } | 388 } |
| 388 | 389 |
| 389 return token; | 390 return token; |
| 390 } | 391 } |
| 391 | 392 |
| 392 Value* JSONReader::DecodeNumber(const Token& token) { | 393 Value* JSONReader::DecodeNumber(const Token& token) { |
| 393 const std::wstring num_string(token.begin, token.length); | 394 const std::string num_string(token.begin, token.length); |
| 394 | 395 |
| 395 int num_int; | 396 int num_int; |
| 396 if (StringToInt(WideToUTF8(num_string), &num_int)) | 397 if (StringToInt(num_string, &num_int)) |
| 397 return Value::CreateIntegerValue(num_int); | 398 return Value::CreateIntegerValue(num_int); |
| 398 | 399 |
| 399 double num_double; | 400 double num_double; |
| 400 if (StringToDouble(WideToUTF8(num_string), &num_double) && | 401 if (StringToDouble(num_string, &num_double) && base::IsFinite(num_double)) |
| 401 base::IsFinite(num_double)) | |
| 402 return Value::CreateDoubleValue(num_double); | 402 return Value::CreateDoubleValue(num_double); |
| 403 | 403 |
| 404 return NULL; | 404 return NULL; |
| 405 } | 405 } |
| 406 | 406 |
| 407 JSONReader::Token JSONReader::ParseStringToken() { | 407 JSONReader::Token JSONReader::ParseStringToken() { |
| 408 Token token(Token::STRING, json_pos_, 1); | 408 Token token(Token::STRING, json_pos_, 1); |
| 409 wchar_t c = token.NextChar(); | 409 char c = token.NextChar(); |
| 410 while ('\0' != c) { | 410 while (json_pos_ + token.length < end_pos_) { |
| 411 if ('\\' == c) { | 411 if ('\\' == c) { |
| 412 ++token.length; | 412 ++token.length; |
| 413 c = token.NextChar(); | 413 c = token.NextChar(); |
| 414 // Make sure the escaped char is valid. | 414 // Make sure the escaped char is valid. |
| 415 switch (c) { | 415 switch (c) { |
| 416 case 'x': | 416 case 'x': |
| 417 if (!ReadHexDigits(token, 2)) { | 417 if (!ReadHexDigits(token, 2)) { |
| 418 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); | 418 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); |
| 419 return Token::CreateInvalidToken(); | 419 return Token::CreateInvalidToken(); |
| 420 } | 420 } |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 443 ++token.length; | 443 ++token.length; |
| 444 return token; | 444 return token; |
| 445 } | 445 } |
| 446 ++token.length; | 446 ++token.length; |
| 447 c = token.NextChar(); | 447 c = token.NextChar(); |
| 448 } | 448 } |
| 449 return Token::CreateInvalidToken(); | 449 return Token::CreateInvalidToken(); |
| 450 } | 450 } |
| 451 | 451 |
| 452 Value* JSONReader::DecodeString(const Token& token) { | 452 Value* JSONReader::DecodeString(const Token& token) { |
| 453 std::wstring decoded_str; | 453 std::string decoded_str; |
| 454 decoded_str.reserve(token.length - 2); | 454 decoded_str.reserve(token.length - 2); |
| 455 | 455 |
| 456 for (int i = 1; i < token.length - 1; ++i) { | 456 for (int i = 1; i < token.length - 1; ++i) { |
| 457 wchar_t c = *(token.begin + i); | 457 char c = *(token.begin + i); |
| 458 if ('\\' == c) { | 458 if ('\\' == c) { |
| 459 ++i; | 459 ++i; |
| 460 c = *(token.begin + i); | 460 c = *(token.begin + i); |
| 461 switch (c) { | 461 switch (c) { |
| 462 case '"': | 462 case '"': |
| 463 case '/': | 463 case '/': |
| 464 case '\\': | 464 case '\\': |
| 465 decoded_str.push_back(c); | 465 decoded_str.push_back(c); |
| 466 break; | 466 break; |
| 467 case 'b': | 467 case 'b': |
| 468 decoded_str.push_back('\b'); | 468 decoded_str.push_back('\b'); |
| 469 break; | 469 break; |
| 470 case 'f': | 470 case 'f': |
| 471 decoded_str.push_back('\f'); | 471 decoded_str.push_back('\f'); |
| 472 break; | 472 break; |
| 473 case 'n': | 473 case 'n': |
| 474 decoded_str.push_back('\n'); | 474 decoded_str.push_back('\n'); |
| 475 break; | 475 break; |
| 476 case 'r': | 476 case 'r': |
| 477 decoded_str.push_back('\r'); | 477 decoded_str.push_back('\r'); |
| 478 break; | 478 break; |
| 479 case 't': | 479 case 't': |
| 480 decoded_str.push_back('\t'); | 480 decoded_str.push_back('\t'); |
| 481 break; | 481 break; |
| 482 case 'v': | 482 case 'v': |
| 483 decoded_str.push_back('\v'); | 483 decoded_str.push_back('\v'); |
| 484 break; | 484 break; |
| 485 | 485 |
| 486 case 'x': | 486 case 'x': |
| 487 decoded_str.push_back((HexDigitToInt(*(token.begin + i + 1)) << 4) + | 487 decoded_str.push_back((HexDigitToInt(*(token.begin + i + 1)) << 4) + |
|
Mark Mentovai
2012/03/22 21:06:20
HexStringToInt here too?
| |
| 488 HexDigitToInt(*(token.begin + i + 2))); | 488 HexDigitToInt(*(token.begin + i + 2))); |
|
Mark Mentovai
2012/03/22 21:06:20
All of this +1, +2, +3 stuff seems kind of unsafe.
brettw
2012/03/23 16:29:24
Let's do Mark's suggestion. It's minor compared to
Robert Sesek
2012/03/23 18:40:27
Fine, done.
If it was wrong for 18 releases, I do
| |
| 489 i += 2; | 489 i += 2; |
| 490 break; | 490 break; |
| 491 case 'u': | 491 case 'u': |
| 492 decoded_str.push_back((HexDigitToInt(*(token.begin + i + 1)) << 12 ) + | 492 if (!ConvertUTF16Units(token, &i, &decoded_str)) |
| 493 (HexDigitToInt(*(token.begin + i + 2)) << 8) + | 493 return NULL; |
| 494 (HexDigitToInt(*(token.begin + i + 3)) << 4) + | |
| 495 HexDigitToInt(*(token.begin + i + 4))); | |
| 496 i += 4; | |
| 497 break; | 494 break; |
| 498 | 495 |
| 499 default: | 496 default: |
| 500 // We should only have valid strings at this point. If not, | 497 // We should only have valid strings at this point. If not, |
| 501 // ParseStringToken didn't do it's job. | 498 // ParseStringToken didn't do it's job. |
| 502 NOTREACHED(); | 499 NOTREACHED(); |
| 503 return NULL; | 500 return NULL; |
| 504 } | 501 } |
| 505 } else { | 502 } else { |
| 506 // Not escaped | 503 // Not escaped |
| 507 decoded_str.push_back(c); | 504 decoded_str.push_back(c); |
| 508 } | 505 } |
| 509 } | 506 } |
| 510 return Value::CreateStringValue(WideToUTF16Hack(decoded_str)); | 507 return Value::CreateStringValue(decoded_str); |
| 508 } | |
| 509 | |
| 510 bool JSONReader::ConvertUTF16Units(const Token& token, | |
| 511 int* i, | |
| 512 std::string* dest_string) { | |
| 513 if (*i + 4 >= token.length) | |
| 514 return false; | |
| 515 | |
| 516 // This is a 32-bit field because the shift operations in the | |
| 517 // conversion process below cause MSVC to error about "data loss." | |
| 518 // This only stores UTF-16 code units, though. | |
| 519 // Consume the UTF-16 code unit, which may be a high surrogate. | |
| 520 int code_unit16_high = 0; | |
| 521 if (!HexStringToInt(StringPiece(token.begin + *i + 1, 4), &code_unit16_high)) | |
| 522 return false; | |
| 523 *i += 4; | |
| 524 | |
| 525 // If this is a high surrogate, consume the next code unit to get the | |
| 526 // low surrogate. | |
| 527 int code_unit16_low = 0; | |
| 528 if (CBU16_IS_SURROGATE(code_unit16_high)) { | |
| 529 // Make sure this is the high surrogate. If not, it's an encoding | |
| 530 // error. | |
| 531 if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high)) | |
| 532 return false; | |
| 533 | |
| 534 // Make sure that the token has more characters to consume the | |
| 535 // lower surrogate. | |
| 536 if (*i + 6 >= token.length) | |
| 537 return false; | |
| 538 if (*(++(*i) + token.begin) != '\\' || *(++(*i) + token.begin) != 'u') | |
| 539 return false; | |
| 540 | |
| 541 if (!HexStringToInt(StringPiece(token.begin + *i + 1, 4), &code_unit16_low)) | |
| 542 return false; | |
| 543 *i += 4; | |
| 544 if (!CBU16_IS_SURROGATE(code_unit16_low) || | |
| 545 !CBU16_IS_TRAIL(code_unit16_low)) { | |
| 546 return false; | |
| 547 } | |
| 548 } else if (!CBU16_IS_SINGLE(code_unit16_high)) { | |
| 549 // If this is not a code point, it's an encoding error. | |
| 550 return false; | |
| 551 } | |
| 552 | |
| 553 // Convert the UTF-16 code units to a code point and then to a UTF-8 | |
| 554 // code unit sequence. | |
| 555 char code_point[8] = { 0 }; | |
| 556 size_t offset = 0; | |
| 557 if (!code_unit16_low) { | |
| 558 CBU8_APPEND_UNSAFE(code_point, offset, code_unit16_high); | |
| 559 } else { | |
| 560 uint32 code_unit32 = CBU16_GET_SUPPLEMENTARY(code_unit16_high, | |
| 561 code_unit16_low); | |
| 562 offset = 0; | |
| 563 CBU8_APPEND_UNSAFE(code_point, offset, code_unit32); | |
| 564 } | |
| 565 dest_string->append(code_point); | |
| 566 return true; | |
| 511 } | 567 } |
| 512 | 568 |
| 513 JSONReader::Token JSONReader::ParseToken() { | 569 JSONReader::Token JSONReader::ParseToken() { |
| 514 EatWhitespaceAndComments(); | 570 EatWhitespaceAndComments(); |
| 515 | 571 |
| 516 Token token(Token::INVALID_TOKEN, 0, 0); | 572 Token token(Token::INVALID_TOKEN, 0, 0); |
| 517 switch (*json_pos_) { | 573 switch (*json_pos_) { |
| 518 case '\0': | 574 case '\0': |
| 519 token.type = Token::END_OF_INPUT; | 575 token.type = Token::END_OF_INPUT; |
| 520 break; | 576 break; |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 573 break; | 629 break; |
| 574 | 630 |
| 575 case '"': | 631 case '"': |
| 576 token = ParseStringToken(); | 632 token = ParseStringToken(); |
| 577 break; | 633 break; |
| 578 } | 634 } |
| 579 return token; | 635 return token; |
| 580 } | 636 } |
| 581 | 637 |
| 582 void JSONReader::EatWhitespaceAndComments() { | 638 void JSONReader::EatWhitespaceAndComments() { |
| 583 while ('\0' != *json_pos_) { | 639 while (json_pos_ != end_pos_) { |
| 584 switch (*json_pos_) { | 640 switch (*json_pos_) { |
| 585 case ' ': | 641 case ' ': |
| 586 case '\n': | 642 case '\n': |
| 587 case '\r': | 643 case '\r': |
| 588 case '\t': | 644 case '\t': |
| 589 ++json_pos_; | 645 ++json_pos_; |
| 590 break; | 646 break; |
| 591 case '/': | 647 case '/': |
| 592 // TODO(tc): This isn't in the RFC so it should be a parser flag. | 648 // TODO(tc): This isn't in the RFC so it should be a parser flag. |
| 593 if (!EatComment()) | 649 if (!EatComment()) |
| 594 return; | 650 return; |
| 595 break; | 651 break; |
| 596 default: | 652 default: |
| 597 // Not a whitespace char, just exit. | 653 // Not a whitespace char, just exit. |
| 598 return; | 654 return; |
| 599 } | 655 } |
| 600 } | 656 } |
| 601 } | 657 } |
| 602 | 658 |
| 603 bool JSONReader::EatComment() { | 659 bool JSONReader::EatComment() { |
| 604 if ('/' != *json_pos_) | 660 if ('/' != *json_pos_) |
| 605 return false; | 661 return false; |
| 606 | 662 |
| 607 wchar_t next_char = *(json_pos_ + 1); | 663 char next_char = *(json_pos_ + 1); |
| 608 if ('/' == next_char) { | 664 if ('/' == next_char) { |
| 609 // Line comment, read until \n or \r | 665 // Line comment, read until \n or \r |
| 610 json_pos_ += 2; | 666 json_pos_ += 2; |
| 611 while ('\0' != *json_pos_) { | 667 while (json_pos_ != end_pos_) { |
| 612 switch (*json_pos_) { | 668 switch (*json_pos_) { |
| 613 case '\n': | 669 case '\n': |
| 614 case '\r': | 670 case '\r': |
| 615 ++json_pos_; | 671 ++json_pos_; |
| 616 return true; | 672 return true; |
| 617 default: | 673 default: |
| 618 ++json_pos_; | 674 ++json_pos_; |
| 619 } | 675 } |
| 620 } | 676 } |
| 621 } else if ('*' == next_char) { | 677 } else if ('*' == next_char) { |
| 622 // Block comment, read until */ | 678 // Block comment, read until */ |
| 623 json_pos_ += 2; | 679 json_pos_ += 2; |
| 624 while ('\0' != *json_pos_) { | 680 while (json_pos_ != end_pos_) { |
| 625 if ('*' == *json_pos_ && '/' == *(json_pos_ + 1)) { | 681 if ('*' == *json_pos_ && '/' == *(json_pos_ + 1)) { |
| 626 json_pos_ += 2; | 682 json_pos_ += 2; |
| 627 return true; | 683 return true; |
| 628 } | 684 } |
| 629 ++json_pos_; | 685 ++json_pos_; |
| 630 } | 686 } |
| 631 } else { | 687 } else { |
| 632 return false; | 688 return false; |
| 633 } | 689 } |
| 634 return true; | 690 return true; |
| 635 } | 691 } |
| 636 | 692 |
| 637 bool JSONReader::NextStringMatch(const wchar_t* str, size_t length) { | 693 bool JSONReader::NextStringMatch(const char* str, size_t length) { |
| 638 return wcsncmp(json_pos_, str, length) == 0; | 694 return strncmp(json_pos_, str, length) == 0; |
| 639 } | 695 } |
| 640 | 696 |
| 641 void JSONReader::SetErrorCode(JsonParseError error, | 697 void JSONReader::SetErrorCode(JsonParseError error, |
| 642 const wchar_t* error_pos) { | 698 const char* error_pos) { |
| 643 int line_number = 1; | 699 int line_number = 1; |
| 644 int column_number = 1; | 700 int column_number = 1; |
| 645 | 701 |
| 646 // Figure out the line and column the error occured at. | 702 // Figure out the line and column the error occured at. |
| 647 for (const wchar_t* pos = start_pos_; pos != error_pos; ++pos) { | 703 for (const char* pos = start_pos_; pos != error_pos; ++pos) { |
| 648 if (*pos == '\0') { | 704 if (pos > end_pos_) { |
| 649 NOTREACHED(); | 705 NOTREACHED(); |
| 650 return; | 706 return; |
| 651 } | 707 } |
| 652 | 708 |
| 653 if (*pos == '\n') { | 709 if (*pos == '\n') { |
| 654 ++line_number; | 710 ++line_number; |
| 655 column_number = 1; | 711 column_number = 1; |
| 656 } else { | 712 } else { |
| 657 ++column_number; | 713 ++column_number; |
| 658 } | 714 } |
| 659 } | 715 } |
| 660 | 716 |
| 661 error_line_ = line_number; | 717 error_line_ = line_number; |
| 662 error_col_ = column_number; | 718 error_col_ = column_number; |
| 663 error_code_ = error; | 719 error_code_ = error; |
| 664 } | 720 } |
| 665 | 721 |
| 666 } // namespace base | 722 } // namespace base |
| OLD | NEW |