| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |