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 |