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 |