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_util.h" | 12 #include "base/string_util.h" |
13 #include "base/utf_string_conversions.h" | 13 #include "base/utf_string_conversions.h" |
14 #include "base/values.h" | 14 #include "base/values.h" |
15 | 15 |
16 namespace { | 16 namespace { |
17 | 17 |
18 const wchar_t kNullString[] = L"null"; | 18 const wchar_t kNullString[] = L"null"; |
19 const wchar_t kTrueString[] = L"true"; | 19 const wchar_t kTrueString[] = L"true"; |
20 const wchar_t kFalseString[] = L"false"; | 20 const wchar_t kFalseString[] = L"false"; |
21 | 21 |
22 const int kStackLimit = 100; | 22 const int kStackLimit = 100; |
23 | 23 |
24 } // namespace | |
25 | |
26 namespace base { | |
27 | |
28 static const JSONReader::Token kInvalidToken(JSONReader::Token::INVALID_TOKEN, | |
29 0, 0); | |
30 namespace { | |
31 | |
32 // A helper method for ParseNumberToken. It reads an int from the end of | 24 // A helper method for ParseNumberToken. It reads an int from the end of |
33 // token. The method returns false if there is no valid integer at the end of | 25 // token. The method returns false if there is no valid integer at the end of |
34 // the token. | 26 // the token. |
35 bool ReadInt(JSONReader::Token& token, bool can_have_leading_zeros) { | 27 bool ReadInt(base::JSONReader::Token& token, bool can_have_leading_zeros) { |
36 wchar_t first = token.NextChar(); | 28 wchar_t first = token.NextChar(); |
37 int len = 0; | 29 int len = 0; |
38 | 30 |
39 // Read in more digits | 31 // Read in more digits |
40 wchar_t c = first; | 32 wchar_t c = first; |
41 while ('\0' != c && '0' <= c && c <= '9') { | 33 while ('\0' != c && '0' <= c && c <= '9') { |
42 ++token.length; | 34 ++token.length; |
43 ++len; | 35 ++len; |
44 c = token.NextChar(); | 36 c = token.NextChar(); |
45 } | 37 } |
46 // We need at least 1 digit. | 38 // We need at least 1 digit. |
47 if (len == 0) | 39 if (len == 0) |
48 return false; | 40 return false; |
49 | 41 |
50 if (!can_have_leading_zeros && len > 1 && '0' == first) | 42 if (!can_have_leading_zeros && len > 1 && '0' == first) |
51 return false; | 43 return false; |
52 | 44 |
53 return true; | 45 return true; |
54 } | 46 } |
55 | 47 |
56 // A helper method for ParseStringToken. It reads |digits| hex digits from the | 48 // A helper method for ParseStringToken. It reads |digits| hex digits from the |
57 // token. If the sequence if digits is not valid (contains other characters), | 49 // token. If the sequence if digits is not valid (contains other characters), |
58 // the method returns false. | 50 // the method returns false. |
59 bool ReadHexDigits(JSONReader::Token& token, int digits) { | 51 bool ReadHexDigits(base::JSONReader::Token& token, int digits) { |
60 for (int i = 1; i <= digits; ++i) { | 52 for (int i = 1; i <= digits; ++i) { |
61 wchar_t c = *(token.begin + token.length + i); | 53 wchar_t c = *(token.begin + token.length + i); |
62 if ('\0' == c) | 54 if ('\0' == c) |
63 return false; | 55 return false; |
64 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || | 56 if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || |
65 ('A' <= c && c <= 'F'))) { | 57 ('A' <= c && c <= 'F'))) { |
66 return false; | 58 return false; |
67 } | 59 } |
68 } | 60 } |
69 | 61 |
70 token.length += digits; | 62 token.length += digits; |
71 return true; | 63 return true; |
72 } | 64 } |
73 | 65 |
74 } // namespace | 66 } // namespace |
75 | 67 |
| 68 namespace base { |
| 69 |
76 const char* JSONReader::kBadRootElementType = | 70 const char* JSONReader::kBadRootElementType = |
77 "Root value must be an array or object."; | 71 "Root value must be an array or object."; |
78 const char* JSONReader::kInvalidEscape = | 72 const char* JSONReader::kInvalidEscape = |
79 "Invalid escape sequence."; | 73 "Invalid escape sequence."; |
80 const char* JSONReader::kSyntaxError = | 74 const char* JSONReader::kSyntaxError = |
81 "Syntax error."; | 75 "Syntax error."; |
82 const char* JSONReader::kTrailingComma = | 76 const char* JSONReader::kTrailingComma = |
83 "Trailing comma not allowed."; | 77 "Trailing comma not allowed."; |
84 const char* JSONReader::kTooMuchNesting = | 78 const char* JSONReader::kTooMuchNesting = |
85 "Too much nesting."; | 79 "Too much nesting."; |
86 const char* JSONReader::kUnexpectedDataAfterRoot = | 80 const char* JSONReader::kUnexpectedDataAfterRoot = |
87 "Unexpected data after root element."; | 81 "Unexpected data after root element."; |
88 const char* JSONReader::kUnsupportedEncoding = | 82 const char* JSONReader::kUnsupportedEncoding = |
89 "Unsupported encoding. JSON must be UTF-8."; | 83 "Unsupported encoding. JSON must be UTF-8."; |
90 const char* JSONReader::kUnquotedDictionaryKey = | 84 const char* JSONReader::kUnquotedDictionaryKey = |
91 "Dictionary keys must be quoted."; | 85 "Dictionary keys must be quoted."; |
92 | 86 |
93 JSONReader::JSONReader() | 87 JSONReader::JSONReader() |
94 : start_pos_(NULL), json_pos_(NULL), stack_depth_(0), | 88 : start_pos_(NULL), |
| 89 json_pos_(NULL), |
| 90 stack_depth_(0), |
95 allow_trailing_comma_(false), | 91 allow_trailing_comma_(false), |
96 error_code_(JSON_NO_ERROR), error_line_(0), error_col_(0) {} | 92 error_code_(JSON_NO_ERROR), |
| 93 error_line_(0), |
| 94 error_col_(0) {} |
97 | 95 |
98 /* static */ | 96 // static |
99 Value* JSONReader::Read(const std::string& json, | 97 Value* JSONReader::Read(const std::string& json, |
100 bool allow_trailing_comma) { | 98 bool allow_trailing_comma) { |
101 return ReadAndReturnError(json, allow_trailing_comma, NULL, NULL); | 99 return ReadAndReturnError(json, allow_trailing_comma, NULL, NULL); |
102 } | 100 } |
103 | 101 |
104 /* static */ | 102 // static |
105 Value* JSONReader::ReadAndReturnError(const std::string& json, | 103 Value* JSONReader::ReadAndReturnError(const std::string& json, |
106 bool allow_trailing_comma, | 104 bool allow_trailing_comma, |
107 int* error_code_out, | 105 int* error_code_out, |
108 std::string* error_msg_out) { | 106 std::string* error_msg_out) { |
109 JSONReader reader = JSONReader(); | 107 JSONReader reader = JSONReader(); |
110 Value* root = reader.JsonToValue(json, true, allow_trailing_comma); | 108 Value* root = reader.JsonToValue(json, true, allow_trailing_comma); |
111 if (root) | 109 if (root) |
112 return root; | 110 return root; |
113 | 111 |
114 if (error_code_out) | 112 if (error_code_out) |
115 *error_code_out = reader.error_code(); | 113 *error_code_out = reader.error_code(); |
116 if (error_msg_out) | 114 if (error_msg_out) |
117 *error_msg_out = reader.GetErrorMessage(); | 115 *error_msg_out = reader.GetErrorMessage(); |
118 | 116 |
119 return NULL; | 117 return NULL; |
120 } | 118 } |
121 | 119 |
122 /* static */ | 120 // static |
123 std::string JSONReader::ErrorCodeToString(JsonParseError error_code) { | 121 std::string JSONReader::ErrorCodeToString(JsonParseError error_code) { |
124 switch (error_code) { | 122 switch (error_code) { |
125 case JSON_NO_ERROR: | 123 case JSON_NO_ERROR: |
126 return std::string(); | 124 return std::string(); |
127 case JSON_BAD_ROOT_ELEMENT_TYPE: | 125 case JSON_BAD_ROOT_ELEMENT_TYPE: |
128 return kBadRootElementType; | 126 return kBadRootElementType; |
129 case JSON_INVALID_ESCAPE: | 127 case JSON_INVALID_ESCAPE: |
130 return kInvalidEscape; | 128 return kInvalidEscape; |
131 case JSON_SYNTAX_ERROR: | 129 case JSON_SYNTAX_ERROR: |
132 return kSyntaxError; | 130 return kSyntaxError; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 } | 185 } |
188 } | 186 } |
189 | 187 |
190 // Default to calling errors "syntax errors". | 188 // Default to calling errors "syntax errors". |
191 if (error_code_ == 0) | 189 if (error_code_ == 0) |
192 SetErrorCode(JSON_SYNTAX_ERROR, json_pos_); | 190 SetErrorCode(JSON_SYNTAX_ERROR, json_pos_); |
193 | 191 |
194 return NULL; | 192 return NULL; |
195 } | 193 } |
196 | 194 |
197 /* static */ | 195 // static |
198 std::string JSONReader::FormatErrorMessage(int line, int column, | 196 std::string JSONReader::FormatErrorMessage(int line, int column, |
199 const std::string& description) { | 197 const std::string& description) { |
200 if (line || column) { | 198 if (line || column) { |
201 return base::StringPrintf( | 199 return base::StringPrintf( |
202 "Line: %i, column: %i, %s", line, column, description.c_str()); | 200 "Line: %i, column: %i, %s", line, column, description.c_str()); |
203 } | 201 } |
204 return description; | 202 return description; |
205 } | 203 } |
206 | 204 |
207 Value* JSONReader::BuildValue(bool is_root) { | 205 Value* JSONReader::BuildValue(bool is_root) { |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 // We just grab the number here. We validate the size in DecodeNumber. | 360 // We just grab the number here. We validate the size in DecodeNumber. |
363 // According to RFC4627, a valid number is: [minus] int [frac] [exp] | 361 // According to RFC4627, a valid number is: [minus] int [frac] [exp] |
364 Token token(Token::NUMBER, json_pos_, 0); | 362 Token token(Token::NUMBER, json_pos_, 0); |
365 wchar_t c = *json_pos_; | 363 wchar_t c = *json_pos_; |
366 if ('-' == c) { | 364 if ('-' == c) { |
367 ++token.length; | 365 ++token.length; |
368 c = token.NextChar(); | 366 c = token.NextChar(); |
369 } | 367 } |
370 | 368 |
371 if (!ReadInt(token, false)) | 369 if (!ReadInt(token, false)) |
372 return kInvalidToken; | 370 return Token::CreateInvalidToken(); |
373 | 371 |
374 // Optional fraction part | 372 // Optional fraction part |
375 c = token.NextChar(); | 373 c = token.NextChar(); |
376 if ('.' == c) { | 374 if ('.' == c) { |
377 ++token.length; | 375 ++token.length; |
378 if (!ReadInt(token, true)) | 376 if (!ReadInt(token, true)) |
379 return kInvalidToken; | 377 return Token::CreateInvalidToken(); |
380 c = token.NextChar(); | 378 c = token.NextChar(); |
381 } | 379 } |
382 | 380 |
383 // Optional exponent part | 381 // Optional exponent part |
384 if ('e' == c || 'E' == c) { | 382 if ('e' == c || 'E' == c) { |
385 ++token.length; | 383 ++token.length; |
386 c = token.NextChar(); | 384 c = token.NextChar(); |
387 if ('-' == c || '+' == c) { | 385 if ('-' == c || '+' == c) { |
388 ++token.length; | 386 ++token.length; |
389 c = token.NextChar(); | 387 c = token.NextChar(); |
390 } | 388 } |
391 if (!ReadInt(token, true)) | 389 if (!ReadInt(token, true)) |
392 return kInvalidToken; | 390 return Token::CreateInvalidToken(); |
393 } | 391 } |
394 | 392 |
395 return token; | 393 return token; |
396 } | 394 } |
397 | 395 |
398 Value* JSONReader::DecodeNumber(const Token& token) { | 396 Value* JSONReader::DecodeNumber(const Token& token) { |
399 const std::wstring num_string(token.begin, token.length); | 397 const std::wstring num_string(token.begin, token.length); |
400 | 398 |
401 int num_int; | 399 int num_int; |
402 if (StringToInt(WideToUTF8(num_string), &num_int)) | 400 if (StringToInt(WideToUTF8(num_string), &num_int)) |
(...skipping 12 matching lines...) Expand all Loading... |
415 wchar_t c = token.NextChar(); | 413 wchar_t c = token.NextChar(); |
416 while ('\0' != c) { | 414 while ('\0' != c) { |
417 if ('\\' == c) { | 415 if ('\\' == c) { |
418 ++token.length; | 416 ++token.length; |
419 c = token.NextChar(); | 417 c = token.NextChar(); |
420 // Make sure the escaped char is valid. | 418 // Make sure the escaped char is valid. |
421 switch (c) { | 419 switch (c) { |
422 case 'x': | 420 case 'x': |
423 if (!ReadHexDigits(token, 2)) { | 421 if (!ReadHexDigits(token, 2)) { |
424 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); | 422 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); |
425 return kInvalidToken; | 423 return Token::CreateInvalidToken(); |
426 } | 424 } |
427 break; | 425 break; |
428 case 'u': | 426 case 'u': |
429 if (!ReadHexDigits(token, 4)) { | 427 if (!ReadHexDigits(token, 4)) { |
430 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); | 428 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); |
431 return kInvalidToken; | 429 return Token::CreateInvalidToken(); |
432 } | 430 } |
433 break; | 431 break; |
434 case '\\': | 432 case '\\': |
435 case '/': | 433 case '/': |
436 case 'b': | 434 case 'b': |
437 case 'f': | 435 case 'f': |
438 case 'n': | 436 case 'n': |
439 case 'r': | 437 case 'r': |
440 case 't': | 438 case 't': |
441 case 'v': | 439 case 'v': |
442 case '"': | 440 case '"': |
443 break; | 441 break; |
444 default: | 442 default: |
445 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); | 443 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); |
446 return kInvalidToken; | 444 return Token::CreateInvalidToken(); |
447 } | 445 } |
448 } else if ('"' == c) { | 446 } else if ('"' == c) { |
449 ++token.length; | 447 ++token.length; |
450 return token; | 448 return token; |
451 } | 449 } |
452 ++token.length; | 450 ++token.length; |
453 c = token.NextChar(); | 451 c = token.NextChar(); |
454 } | 452 } |
455 return kInvalidToken; | 453 return Token::CreateInvalidToken(); |
456 } | 454 } |
457 | 455 |
458 Value* JSONReader::DecodeString(const Token& token) { | 456 Value* JSONReader::DecodeString(const Token& token) { |
459 std::wstring decoded_str; | 457 std::wstring decoded_str; |
460 decoded_str.reserve(token.length - 2); | 458 decoded_str.reserve(token.length - 2); |
461 | 459 |
462 for (int i = 1; i < token.length - 1; ++i) { | 460 for (int i = 1; i < token.length - 1; ++i) { |
463 wchar_t c = *(token.begin + i); | 461 wchar_t c = *(token.begin + i); |
464 if ('\\' == c) { | 462 if ('\\' == c) { |
465 ++i; | 463 ++i; |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
663 ++column_number; | 661 ++column_number; |
664 } | 662 } |
665 } | 663 } |
666 | 664 |
667 error_line_ = line_number; | 665 error_line_ = line_number; |
668 error_col_ = column_number; | 666 error_col_ = column_number; |
669 error_code_ = error; | 667 error_code_ = error; |
670 } | 668 } |
671 | 669 |
672 } // namespace base | 670 } // namespace base |
OLD | NEW |