Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: base/json_reader.cc

Issue 16270: Change the signature of JSONReader::Read() and related methods to be more (Closed)
Patch Set: fixens Created 11 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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_reader.h" 5 #include "base/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/string_util.h" 9 #include "base/string_util.h"
10 #include "base/values.h" 10 #include "base/values.h"
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 const char* JSONReader::kTooMuchNesting = 82 const char* JSONReader::kTooMuchNesting =
83 "Too much nesting."; 83 "Too much nesting.";
84 const char* JSONReader::kUnexpectedDataAfterRoot = 84 const char* JSONReader::kUnexpectedDataAfterRoot =
85 "Unexpected data after root element."; 85 "Unexpected data after root element.";
86 const char* JSONReader::kUnsupportedEncoding = 86 const char* JSONReader::kUnsupportedEncoding =
87 "Unsupported encoding. JSON must be UTF-8."; 87 "Unsupported encoding. JSON must be UTF-8.";
88 const char* JSONReader::kUnquotedDictionaryKey = 88 const char* JSONReader::kUnquotedDictionaryKey =
89 "Dictionary keys must be quoted."; 89 "Dictionary keys must be quoted.";
90 90
91 /* static */ 91 /* static */
92 bool JSONReader::Read(const std::string& json, 92 Value* JSONReader::Read(const std::string& json,
93 Value** root, 93 bool allow_trailing_comma) {
94 bool allow_trailing_comma) { 94 return ReadAndReturnError(json, allow_trailing_comma, NULL);
95 return ReadAndReturnError(json, root, allow_trailing_comma, NULL);
96 } 95 }
97 96
98 /* static */ 97 /* static */
99 bool JSONReader::ReadAndReturnError(const std::string& json, 98 Value* JSONReader::ReadAndReturnError(const std::string& json,
100 Value** root, 99 bool allow_trailing_comma,
101 bool allow_trailing_comma, 100 std::string *error_message_out) {
102 std::string *error_message_out) {
103 JSONReader reader = JSONReader(); 101 JSONReader reader = JSONReader();
104 if (reader.JsonToValue(json, root, true, allow_trailing_comma)) { 102 Value* root = reader.JsonToValue(json, true, allow_trailing_comma);
105 return true; 103 if (root)
106 } else { 104 return root;
107 if (error_message_out) 105
108 *error_message_out = reader.error_message(); 106 if (error_message_out)
109 return false; 107 *error_message_out = reader.error_message();
110 } 108
109 return NULL;
111 } 110 }
112 111
113 /* static */ 112 /* static */
114 std::string JSONReader::FormatErrorMessage(int line, int column, 113 std::string JSONReader::FormatErrorMessage(int line, int column,
115 const char* description) { 114 const char* description) {
116 return StringPrintf("Line: %i, column: %i, %s", 115 return StringPrintf("Line: %i, column: %i, %s",
117 line, column, description); 116 line, column, description);
118 } 117 }
119 118
120 JSONReader::JSONReader() 119 JSONReader::JSONReader()
121 : start_pos_(NULL), json_pos_(NULL), stack_depth_(0), 120 : start_pos_(NULL), json_pos_(NULL), stack_depth_(0),
122 allow_trailing_comma_(false) {} 121 allow_trailing_comma_(false) {}
123 122
124 bool JSONReader::JsonToValue(const std::string& json, Value** root, 123 Value* JSONReader::JsonToValue(const std::string& json, bool check_root,
125 bool check_root, bool allow_trailing_comma) { 124 bool allow_trailing_comma) {
126 // The input must be in UTF-8. 125 // The input must be in UTF-8.
127 if (!IsStringUTF8(json.c_str())) { 126 if (!IsStringUTF8(json.c_str())) {
128 error_message_ = kUnsupportedEncoding; 127 error_message_ = kUnsupportedEncoding;
129 return false; 128 return NULL;
130 } 129 }
131 130
132 // The conversion from UTF8 to wstring removes null bytes for us 131 // The conversion from UTF8 to wstring removes null bytes for us
133 // (a good thing). 132 // (a good thing).
134 std::wstring json_wide(UTF8ToWide(json)); 133 std::wstring json_wide(UTF8ToWide(json));
135 start_pos_ = json_wide.c_str(); 134 start_pos_ = json_wide.c_str();
136 135
137 // When the input JSON string starts with a UTF-8 Byte-Order-Mark 136 // When the input JSON string starts with a UTF-8 Byte-Order-Mark
138 // (0xEF, 0xBB, 0xBF), the UTF8ToWide() function converts it to a Unicode 137 // (0xEF, 0xBB, 0xBF), the UTF8ToWide() function converts it to a Unicode
139 // BOM (U+FEFF). To avoid the JSONReader::BuildValue() function from 138 // BOM (U+FEFF). To avoid the JSONReader::BuildValue() function from
140 // mis-treating a Unicode BOM as an invalid character and returning false, 139 // mis-treating a Unicode BOM as an invalid character and returning false,
141 // skip a converted Unicode BOM if it exists. 140 // skip a converted Unicode BOM if it exists.
142 if (!json_wide.empty() && start_pos_[0] == 0xFEFF) { 141 if (!json_wide.empty() && start_pos_[0] == 0xFEFF) {
143 ++start_pos_; 142 ++start_pos_;
144 } 143 }
145 144
146 json_pos_ = start_pos_; 145 json_pos_ = start_pos_;
147 allow_trailing_comma_ = allow_trailing_comma; 146 allow_trailing_comma_ = allow_trailing_comma;
148 stack_depth_ = 0; 147 stack_depth_ = 0;
149 error_message_.clear(); 148 error_message_.clear();
150 149
151 Value* temp_root = NULL; 150 scoped_ptr<Value> root(BuildValue(check_root));
152 151 if (root.get()) {
153 // Only modify root_ if we have valid JSON and nothing else.
154 if (BuildValue(&temp_root, check_root)) {
155 if (ParseToken().type == Token::END_OF_INPUT) { 152 if (ParseToken().type == Token::END_OF_INPUT) {
156 *root = temp_root; 153 return root.release();
157 return true;
158 } else { 154 } else {
159 SetErrorMessage(kUnexpectedDataAfterRoot, json_pos_); 155 SetErrorMessage(kUnexpectedDataAfterRoot, json_pos_);
160 } 156 }
161 } 157 }
162 158
163 // Default to calling errors "syntax errors". 159 // Default to calling errors "syntax errors".
164 if (error_message_.empty()) 160 if (error_message_.empty())
165 SetErrorMessage(kSyntaxError, json_pos_); 161 SetErrorMessage(kSyntaxError, json_pos_);
166 162
167 if (temp_root) 163 return NULL;
168 delete temp_root;
169 return false;
170 } 164 }
171 165
172 bool JSONReader::BuildValue(Value** node, bool is_root) { 166 Value* JSONReader::BuildValue(bool is_root) {
173 ++stack_depth_; 167 ++stack_depth_;
174 if (stack_depth_ > kStackLimit) { 168 if (stack_depth_ > kStackLimit) {
175 SetErrorMessage(kTooMuchNesting, json_pos_); 169 SetErrorMessage(kTooMuchNesting, json_pos_);
176 return false; 170 return NULL;
177 } 171 }
178 172
179 Token token = ParseToken(); 173 Token token = ParseToken();
180 // The root token must be an array or an object. 174 // The root token must be an array or an object.
181 if (is_root && token.type != Token::OBJECT_BEGIN && 175 if (is_root && token.type != Token::OBJECT_BEGIN &&
182 token.type != Token::ARRAY_BEGIN) { 176 token.type != Token::ARRAY_BEGIN) {
183 SetErrorMessage(kBadRootElementType, json_pos_); 177 SetErrorMessage(kBadRootElementType, json_pos_);
184 return false; 178 return NULL;
185 } 179 }
186 180
181 scoped_ptr<Value> node;
182
187 switch (token.type) { 183 switch (token.type) {
188 case Token::END_OF_INPUT: 184 case Token::END_OF_INPUT:
189 case Token::INVALID_TOKEN: 185 case Token::INVALID_TOKEN:
190 return false; 186 return NULL;
191 187
192 case Token::NULL_TOKEN: 188 case Token::NULL_TOKEN:
193 *node = Value::CreateNullValue(); 189 node.reset(Value::CreateNullValue());
194 break; 190 break;
195 191
196 case Token::BOOL_TRUE: 192 case Token::BOOL_TRUE:
197 *node = Value::CreateBooleanValue(true); 193 node.reset(Value::CreateBooleanValue(true));
198 break; 194 break;
199 195
200 case Token::BOOL_FALSE: 196 case Token::BOOL_FALSE:
201 *node = Value::CreateBooleanValue(false); 197 node.reset(Value::CreateBooleanValue(false));
202 break; 198 break;
203 199
204 case Token::NUMBER: 200 case Token::NUMBER:
205 if (!DecodeNumber(token, node)) 201 node.reset(DecodeNumber(token));
206 return false; 202 if (!node.get())
203 return NULL;
207 break; 204 break;
208 205
209 case Token::STRING: 206 case Token::STRING:
210 if (!DecodeString(token, node)) 207 node.reset(DecodeString(token));
211 return false; 208 if (!node.get())
209 return NULL;
212 break; 210 break;
213 211
214 case Token::ARRAY_BEGIN: 212 case Token::ARRAY_BEGIN:
215 { 213 {
216 json_pos_ += token.length; 214 json_pos_ += token.length;
217 token = ParseToken(); 215 token = ParseToken();
218 216
219 ListValue* array = new ListValue; 217 node.reset(new ListValue());
220 while (token.type != Token::ARRAY_END) { 218 while (token.type != Token::ARRAY_END) {
221 Value* array_node = NULL; 219 Value* array_node = BuildValue(false);
222 if (!BuildValue(&array_node, false)) { 220 if (!array_node) {
223 delete array; 221 return NULL;
224 return false;
225 } 222 }
226 array->Append(array_node); 223 static_cast<ListValue*>(node.get())->Append(array_node);
227 224
228 // After a list value, we expect a comma or the end of the list. 225 // After a list value, we expect a comma or the end of the list.
229 token = ParseToken(); 226 token = ParseToken();
230 if (token.type == Token::LIST_SEPARATOR) { 227 if (token.type == Token::LIST_SEPARATOR) {
231 json_pos_ += token.length; 228 json_pos_ += token.length;
232 token = ParseToken(); 229 token = ParseToken();
233 // Trailing commas are invalid according to the JSON RFC, but some 230 // Trailing commas are invalid according to the JSON RFC, but some
234 // consumers need the parsing leniency, so handle accordingly. 231 // consumers need the parsing leniency, so handle accordingly.
235 if (token.type == Token::ARRAY_END) { 232 if (token.type == Token::ARRAY_END) {
236 if (!allow_trailing_comma_) { 233 if (!allow_trailing_comma_) {
237 SetErrorMessage(kTrailingComma, json_pos_); 234 SetErrorMessage(kTrailingComma, json_pos_);
238 delete array; 235 return NULL;
239 return false;
240 } 236 }
241 // Trailing comma OK, stop parsing the Array. 237 // Trailing comma OK, stop parsing the Array.
242 break; 238 break;
243 } 239 }
244 } else if (token.type != Token::ARRAY_END) { 240 } else if (token.type != Token::ARRAY_END) {
245 // Unexpected value after list value. Bail out. 241 // Unexpected value after list value. Bail out.
246 delete array; 242 return NULL;
247 return false;
248 } 243 }
249 } 244 }
250 if (token.type != Token::ARRAY_END) { 245 if (token.type != Token::ARRAY_END) {
251 delete array; 246 return NULL;
252 return false;
253 } 247 }
254 *node = array;
255 break; 248 break;
256 } 249 }
257 250
258 case Token::OBJECT_BEGIN: 251 case Token::OBJECT_BEGIN:
259 { 252 {
260 json_pos_ += token.length; 253 json_pos_ += token.length;
261 token = ParseToken(); 254 token = ParseToken();
262 255
263 DictionaryValue* dict = new DictionaryValue; 256 node.reset(new DictionaryValue);
264 while (token.type != Token::OBJECT_END) { 257 while (token.type != Token::OBJECT_END) {
265 if (token.type != Token::STRING) { 258 if (token.type != Token::STRING) {
266 SetErrorMessage(kUnquotedDictionaryKey, json_pos_); 259 SetErrorMessage(kUnquotedDictionaryKey, json_pos_);
267 delete dict; 260 return NULL;
268 return false;
269 } 261 }
270 Value* dict_key_value = NULL; 262 scoped_ptr<Value> dict_key_value(DecodeString(token));
271 if (!DecodeString(token, &dict_key_value)) { 263 if (!dict_key_value.get())
272 delete dict; 264 return NULL;
273 return false; 265
274 }
275 // Convert the key into a wstring. 266 // Convert the key into a wstring.
276 std::wstring dict_key; 267 std::wstring dict_key;
277 bool success = dict_key_value->GetAsString(&dict_key); 268 bool success = dict_key_value->GetAsString(&dict_key);
278 DCHECK(success); 269 DCHECK(success);
279 delete dict_key_value;
280 270
281 json_pos_ += token.length; 271 json_pos_ += token.length;
282 token = ParseToken(); 272 token = ParseToken();
283 if (token.type != Token::OBJECT_PAIR_SEPARATOR) { 273 if (token.type != Token::OBJECT_PAIR_SEPARATOR)
284 delete dict; 274 return NULL;
285 return false;
286 }
287 275
288 json_pos_ += token.length; 276 json_pos_ += token.length;
289 token = ParseToken(); 277 token = ParseToken();
290 Value* dict_value = NULL; 278 Value* dict_value = BuildValue(false);
291 if (!BuildValue(&dict_value, false)) { 279 if (!dict_value)
292 delete dict; 280 return NULL;
293 return false; 281 static_cast<DictionaryValue*>(node.get())->Set(dict_key, dict_value);
294 }
295 dict->Set(dict_key, dict_value);
296 282
297 // After a key/value pair, we expect a comma or the end of the 283 // After a key/value pair, we expect a comma or the end of the
298 // object. 284 // object.
299 token = ParseToken(); 285 token = ParseToken();
300 if (token.type == Token::LIST_SEPARATOR) { 286 if (token.type == Token::LIST_SEPARATOR) {
301 json_pos_ += token.length; 287 json_pos_ += token.length;
302 token = ParseToken(); 288 token = ParseToken();
303 // Trailing commas are invalid according to the JSON RFC, but some 289 // Trailing commas are invalid according to the JSON RFC, but some
304 // consumers need the parsing leniency, so handle accordingly. 290 // consumers need the parsing leniency, so handle accordingly.
305 if (token.type == Token::OBJECT_END) { 291 if (token.type == Token::OBJECT_END) {
306 if (!allow_trailing_comma_) { 292 if (!allow_trailing_comma_) {
307 SetErrorMessage(kTrailingComma, json_pos_); 293 SetErrorMessage(kTrailingComma, json_pos_);
308 delete dict; 294 return NULL;
309 return false;
310 } 295 }
311 // Trailing comma OK, stop parsing the Object. 296 // Trailing comma OK, stop parsing the Object.
312 break; 297 break;
313 } 298 }
314 } else if (token.type != Token::OBJECT_END) { 299 } else if (token.type != Token::OBJECT_END) {
315 // Unexpected value after last object value. Bail out. 300 // Unexpected value after last object value. Bail out.
316 delete dict; 301 return NULL;
317 return false;
318 } 302 }
319 } 303 }
320 if (token.type != Token::OBJECT_END) { 304 if (token.type != Token::OBJECT_END)
321 delete dict; 305 return NULL;
322 return false; 306
323 }
324 *node = dict;
325 break; 307 break;
326 } 308 }
327 309
328 default: 310 default:
329 // We got a token that's not a value. 311 // We got a token that's not a value.
330 return false; 312 return NULL;
331 } 313 }
332 json_pos_ += token.length; 314 json_pos_ += token.length;
333 315
334 --stack_depth_; 316 --stack_depth_;
335 return true; 317 return node.release();
336 } 318 }
337 319
338 JSONReader::Token JSONReader::ParseNumberToken() { 320 JSONReader::Token JSONReader::ParseNumberToken() {
339 // We just grab the number here. We validate the size in DecodeNumber. 321 // We just grab the number here. We validate the size in DecodeNumber.
340 // According to RFC4627, a valid number is: [minus] int [frac] [exp] 322 // According to RFC4627, a valid number is: [minus] int [frac] [exp]
341 Token token(Token::NUMBER, json_pos_, 0); 323 Token token(Token::NUMBER, json_pos_, 0);
342 wchar_t c = *json_pos_; 324 wchar_t c = *json_pos_;
343 if ('-' == c) { 325 if ('-' == c) {
344 ++token.length; 326 ++token.length;
345 c = token.NextChar(); 327 c = token.NextChar();
(...skipping 19 matching lines...) Expand all
365 ++token.length; 347 ++token.length;
366 c = token.NextChar(); 348 c = token.NextChar();
367 } 349 }
368 if (!ReadInt(token, true)) 350 if (!ReadInt(token, true))
369 return kInvalidToken; 351 return kInvalidToken;
370 } 352 }
371 353
372 return token; 354 return token;
373 } 355 }
374 356
375 bool JSONReader::DecodeNumber(const Token& token, Value** node) { 357 Value* JSONReader::DecodeNumber(const Token& token) {
376 const std::wstring num_string(token.begin, token.length); 358 const std::wstring num_string(token.begin, token.length);
377 359
378 int num_int; 360 int num_int;
379 if (StringToInt(num_string, &num_int)) { 361 if (StringToInt(num_string, &num_int))
380 *node = Value::CreateIntegerValue(num_int); 362 return Value::CreateIntegerValue(num_int);
381 return true;
382 }
383 363
384 double num_double; 364 double num_double;
385 if (StringToDouble(num_string, &num_double) && base::IsFinite(num_double)) { 365 if (StringToDouble(num_string, &num_double) && base::IsFinite(num_double))
386 *node = Value::CreateRealValue(num_double); 366 return Value::CreateRealValue(num_double);
387 return true;
388 }
389 367
390 return false; 368 return NULL;
391 } 369 }
392 370
393 JSONReader::Token JSONReader::ParseStringToken() { 371 JSONReader::Token JSONReader::ParseStringToken() {
394 Token token(Token::STRING, json_pos_, 1); 372 Token token(Token::STRING, json_pos_, 1);
395 wchar_t c = token.NextChar(); 373 wchar_t c = token.NextChar();
396 while ('\0' != c) { 374 while ('\0' != c) {
397 if ('\\' == c) { 375 if ('\\' == c) {
398 ++token.length; 376 ++token.length;
399 c = token.NextChar(); 377 c = token.NextChar();
400 // Make sure the escaped char is valid. 378 // Make sure the escaped char is valid.
(...skipping 27 matching lines...) Expand all
428 } else if ('"' == c) { 406 } else if ('"' == c) {
429 ++token.length; 407 ++token.length;
430 return token; 408 return token;
431 } 409 }
432 ++token.length; 410 ++token.length;
433 c = token.NextChar(); 411 c = token.NextChar();
434 } 412 }
435 return kInvalidToken; 413 return kInvalidToken;
436 } 414 }
437 415
438 bool JSONReader::DecodeString(const Token& token, Value** node) { 416 Value* JSONReader::DecodeString(const Token& token) {
439 std::wstring decoded_str; 417 std::wstring decoded_str;
440 decoded_str.reserve(token.length - 2); 418 decoded_str.reserve(token.length - 2);
441 419
442 for (int i = 1; i < token.length - 1; ++i) { 420 for (int i = 1; i < token.length - 1; ++i) {
443 wchar_t c = *(token.begin + i); 421 wchar_t c = *(token.begin + i);
444 if ('\\' == c) { 422 if ('\\' == c) {
445 ++i; 423 ++i;
446 c = *(token.begin + i); 424 c = *(token.begin + i);
447 switch (c) { 425 switch (c) {
448 case '"': 426 case '"':
(...skipping 30 matching lines...) Expand all
479 (HexToInt(*(token.begin + i + 2)) << 8) + 457 (HexToInt(*(token.begin + i + 2)) << 8) +
480 (HexToInt(*(token.begin + i + 3)) << 4) + 458 (HexToInt(*(token.begin + i + 3)) << 4) +
481 HexToInt(*(token.begin + i + 4))); 459 HexToInt(*(token.begin + i + 4)));
482 i += 4; 460 i += 4;
483 break; 461 break;
484 462
485 default: 463 default:
486 // We should only have valid strings at this point. If not, 464 // We should only have valid strings at this point. If not,
487 // ParseStringToken didn't do it's job. 465 // ParseStringToken didn't do it's job.
488 NOTREACHED(); 466 NOTREACHED();
489 return false; 467 return NULL;
490 } 468 }
491 } else { 469 } else {
492 // Not escaped 470 // Not escaped
493 decoded_str.push_back(c); 471 decoded_str.push_back(c);
494 } 472 }
495 } 473 }
496 *node = Value::CreateStringValue(decoded_str); 474 return Value::CreateStringValue(decoded_str);
497
498 return true;
499 } 475 }
500 476
501 JSONReader::Token JSONReader::ParseToken() { 477 JSONReader::Token JSONReader::ParseToken() {
502 static const std::wstring kNullString(L"null"); 478 static const std::wstring kNullString(L"null");
503 static const std::wstring kTrueString(L"true"); 479 static const std::wstring kTrueString(L"true");
504 static const std::wstring kFalseString(L"false"); 480 static const std::wstring kFalseString(L"false");
505 481
506 EatWhitespaceAndComments(); 482 EatWhitespaceAndComments();
507 483
508 Token token(Token::INVALID_TOKEN, 0, 0); 484 Token token(Token::INVALID_TOKEN, 0, 0);
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
655 if (*pos == '\n') { 631 if (*pos == '\n') {
656 ++line_number; 632 ++line_number;
657 column_number = 1; 633 column_number = 1;
658 } else { 634 } else {
659 ++column_number; 635 ++column_number;
660 } 636 }
661 } 637 }
662 638
663 error_message_ = FormatErrorMessage(line_number, column_number, description); 639 error_message_ = FormatErrorMessage(line_number, column_number, description);
664 } 640 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698