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 : kInvalidToken(new Token(Token::INVALID_TOKEN, 0, 0)), |
tfarina
2011/09/01 01:21:07
I'm not convinced this is the best way to do this.
tony
2011/09/01 01:48:11
I think we should just get rid of kInvalidToken an
| |
89 start_pos_(NULL), | |
90 json_pos_(NULL), | |
91 stack_depth_(0), | |
95 allow_trailing_comma_(false), | 92 allow_trailing_comma_(false), |
96 error_code_(JSON_NO_ERROR), error_line_(0), error_col_(0) {} | 93 error_code_(JSON_NO_ERROR), |
94 error_line_(0), | |
95 error_col_(0) {} | |
97 | 96 |
98 /* static */ | 97 // static |
99 Value* JSONReader::Read(const std::string& json, | 98 Value* JSONReader::Read(const std::string& json, |
100 bool allow_trailing_comma) { | 99 bool allow_trailing_comma) { |
101 return ReadAndReturnError(json, allow_trailing_comma, NULL, NULL); | 100 return ReadAndReturnError(json, allow_trailing_comma, NULL, NULL); |
102 } | 101 } |
103 | 102 |
104 /* static */ | 103 // static |
105 Value* JSONReader::ReadAndReturnError(const std::string& json, | 104 Value* JSONReader::ReadAndReturnError(const std::string& json, |
106 bool allow_trailing_comma, | 105 bool allow_trailing_comma, |
107 int* error_code_out, | 106 int* error_code_out, |
108 std::string* error_msg_out) { | 107 std::string* error_msg_out) { |
109 JSONReader reader = JSONReader(); | 108 JSONReader reader = JSONReader(); |
110 Value* root = reader.JsonToValue(json, true, allow_trailing_comma); | 109 Value* root = reader.JsonToValue(json, true, allow_trailing_comma); |
111 if (root) | 110 if (root) |
112 return root; | 111 return root; |
113 | 112 |
114 if (error_code_out) | 113 if (error_code_out) |
115 *error_code_out = reader.error_code(); | 114 *error_code_out = reader.error_code(); |
116 if (error_msg_out) | 115 if (error_msg_out) |
117 *error_msg_out = reader.GetErrorMessage(); | 116 *error_msg_out = reader.GetErrorMessage(); |
118 | 117 |
119 return NULL; | 118 return NULL; |
120 } | 119 } |
121 | 120 |
122 /* static */ | 121 // static |
123 std::string JSONReader::ErrorCodeToString(JsonParseError error_code) { | 122 std::string JSONReader::ErrorCodeToString(JsonParseError error_code) { |
124 switch (error_code) { | 123 switch (error_code) { |
125 case JSON_NO_ERROR: | 124 case JSON_NO_ERROR: |
126 return std::string(); | 125 return std::string(); |
127 case JSON_BAD_ROOT_ELEMENT_TYPE: | 126 case JSON_BAD_ROOT_ELEMENT_TYPE: |
128 return kBadRootElementType; | 127 return kBadRootElementType; |
129 case JSON_INVALID_ESCAPE: | 128 case JSON_INVALID_ESCAPE: |
130 return kInvalidEscape; | 129 return kInvalidEscape; |
131 case JSON_SYNTAX_ERROR: | 130 case JSON_SYNTAX_ERROR: |
132 return kSyntaxError; | 131 return kSyntaxError; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
187 } | 186 } |
188 } | 187 } |
189 | 188 |
190 // Default to calling errors "syntax errors". | 189 // Default to calling errors "syntax errors". |
191 if (error_code_ == 0) | 190 if (error_code_ == 0) |
192 SetErrorCode(JSON_SYNTAX_ERROR, json_pos_); | 191 SetErrorCode(JSON_SYNTAX_ERROR, json_pos_); |
193 | 192 |
194 return NULL; | 193 return NULL; |
195 } | 194 } |
196 | 195 |
197 /* static */ | 196 // static |
198 std::string JSONReader::FormatErrorMessage(int line, int column, | 197 std::string JSONReader::FormatErrorMessage(int line, int column, |
199 const std::string& description) { | 198 const std::string& description) { |
200 if (line || column) { | 199 if (line || column) { |
201 return base::StringPrintf( | 200 return base::StringPrintf( |
202 "Line: %i, column: %i, %s", line, column, description.c_str()); | 201 "Line: %i, column: %i, %s", line, column, description.c_str()); |
203 } | 202 } |
204 return description; | 203 return description; |
205 } | 204 } |
206 | 205 |
207 Value* JSONReader::BuildValue(bool is_root) { | 206 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. | 361 // We just grab the number here. We validate the size in DecodeNumber. |
363 // According to RFC4627, a valid number is: [minus] int [frac] [exp] | 362 // According to RFC4627, a valid number is: [minus] int [frac] [exp] |
364 Token token(Token::NUMBER, json_pos_, 0); | 363 Token token(Token::NUMBER, json_pos_, 0); |
365 wchar_t c = *json_pos_; | 364 wchar_t c = *json_pos_; |
366 if ('-' == c) { | 365 if ('-' == c) { |
367 ++token.length; | 366 ++token.length; |
368 c = token.NextChar(); | 367 c = token.NextChar(); |
369 } | 368 } |
370 | 369 |
371 if (!ReadInt(token, false)) | 370 if (!ReadInt(token, false)) |
372 return kInvalidToken; | 371 return *kInvalidToken; |
373 | 372 |
374 // Optional fraction part | 373 // Optional fraction part |
375 c = token.NextChar(); | 374 c = token.NextChar(); |
376 if ('.' == c) { | 375 if ('.' == c) { |
377 ++token.length; | 376 ++token.length; |
378 if (!ReadInt(token, true)) | 377 if (!ReadInt(token, true)) |
379 return kInvalidToken; | 378 return *kInvalidToken; |
380 c = token.NextChar(); | 379 c = token.NextChar(); |
381 } | 380 } |
382 | 381 |
383 // Optional exponent part | 382 // Optional exponent part |
384 if ('e' == c || 'E' == c) { | 383 if ('e' == c || 'E' == c) { |
385 ++token.length; | 384 ++token.length; |
386 c = token.NextChar(); | 385 c = token.NextChar(); |
387 if ('-' == c || '+' == c) { | 386 if ('-' == c || '+' == c) { |
388 ++token.length; | 387 ++token.length; |
389 c = token.NextChar(); | 388 c = token.NextChar(); |
390 } | 389 } |
391 if (!ReadInt(token, true)) | 390 if (!ReadInt(token, true)) |
392 return kInvalidToken; | 391 return *kInvalidToken; |
393 } | 392 } |
394 | 393 |
395 return token; | 394 return token; |
396 } | 395 } |
397 | 396 |
398 Value* JSONReader::DecodeNumber(const Token& token) { | 397 Value* JSONReader::DecodeNumber(const Token& token) { |
399 const std::wstring num_string(token.begin, token.length); | 398 const std::wstring num_string(token.begin, token.length); |
400 | 399 |
401 int num_int; | 400 int num_int; |
402 if (StringToInt(WideToUTF8(num_string), &num_int)) | 401 if (StringToInt(WideToUTF8(num_string), &num_int)) |
(...skipping 12 matching lines...) Expand all Loading... | |
415 wchar_t c = token.NextChar(); | 414 wchar_t c = token.NextChar(); |
416 while ('\0' != c) { | 415 while ('\0' != c) { |
417 if ('\\' == c) { | 416 if ('\\' == c) { |
418 ++token.length; | 417 ++token.length; |
419 c = token.NextChar(); | 418 c = token.NextChar(); |
420 // Make sure the escaped char is valid. | 419 // Make sure the escaped char is valid. |
421 switch (c) { | 420 switch (c) { |
422 case 'x': | 421 case 'x': |
423 if (!ReadHexDigits(token, 2)) { | 422 if (!ReadHexDigits(token, 2)) { |
424 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); | 423 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); |
425 return kInvalidToken; | 424 return *kInvalidToken; |
426 } | 425 } |
427 break; | 426 break; |
428 case 'u': | 427 case 'u': |
429 if (!ReadHexDigits(token, 4)) { | 428 if (!ReadHexDigits(token, 4)) { |
430 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); | 429 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); |
431 return kInvalidToken; | 430 return *kInvalidToken; |
432 } | 431 } |
433 break; | 432 break; |
434 case '\\': | 433 case '\\': |
435 case '/': | 434 case '/': |
436 case 'b': | 435 case 'b': |
437 case 'f': | 436 case 'f': |
438 case 'n': | 437 case 'n': |
439 case 'r': | 438 case 'r': |
440 case 't': | 439 case 't': |
441 case 'v': | 440 case 'v': |
442 case '"': | 441 case '"': |
443 break; | 442 break; |
444 default: | 443 default: |
445 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); | 444 SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); |
446 return kInvalidToken; | 445 return *kInvalidToken; |
447 } | 446 } |
448 } else if ('"' == c) { | 447 } else if ('"' == c) { |
449 ++token.length; | 448 ++token.length; |
450 return token; | 449 return token; |
451 } | 450 } |
452 ++token.length; | 451 ++token.length; |
453 c = token.NextChar(); | 452 c = token.NextChar(); |
454 } | 453 } |
455 return kInvalidToken; | 454 return *kInvalidToken; |
456 } | 455 } |
457 | 456 |
458 Value* JSONReader::DecodeString(const Token& token) { | 457 Value* JSONReader::DecodeString(const Token& token) { |
459 std::wstring decoded_str; | 458 std::wstring decoded_str; |
460 decoded_str.reserve(token.length - 2); | 459 decoded_str.reserve(token.length - 2); |
461 | 460 |
462 for (int i = 1; i < token.length - 1; ++i) { | 461 for (int i = 1; i < token.length - 1; ++i) { |
463 wchar_t c = *(token.begin + i); | 462 wchar_t c = *(token.begin + i); |
464 if ('\\' == c) { | 463 if ('\\' == c) { |
465 ++i; | 464 ++i; |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
663 ++column_number; | 662 ++column_number; |
664 } | 663 } |
665 } | 664 } |
666 | 665 |
667 error_line_ = line_number; | 666 error_line_ = line_number; |
668 error_col_ = column_number; | 667 error_col_ = column_number; |
669 error_code_ = error; | 668 error_code_ = error; |
670 } | 669 } |
671 | 670 |
672 } // namespace base | 671 } // namespace base |
OLD | NEW |