16d528ed9Sopenharmony_ci// Copyright (c) 2012 The Chromium Authors. All rights reserved. 26d528ed9Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 36d528ed9Sopenharmony_ci// found in the LICENSE file. 46d528ed9Sopenharmony_ci 56d528ed9Sopenharmony_ci#include "base/json/json_parser.h" 66d528ed9Sopenharmony_ci 76d528ed9Sopenharmony_ci#include <cmath> 86d528ed9Sopenharmony_ci#include <string_view> 96d528ed9Sopenharmony_ci#include <utility> 106d528ed9Sopenharmony_ci#include <vector> 116d528ed9Sopenharmony_ci 126d528ed9Sopenharmony_ci#include "base/logging.h" 136d528ed9Sopenharmony_ci#include "base/numerics/safe_conversions.h" 146d528ed9Sopenharmony_ci#include "base/strings/string_number_conversions.h" 156d528ed9Sopenharmony_ci#include "base/strings/string_util.h" 166d528ed9Sopenharmony_ci#include "base/strings/stringprintf.h" 176d528ed9Sopenharmony_ci#include "base/strings/utf_string_conversion_utils.h" 186d528ed9Sopenharmony_ci#include "base/strings/utf_string_conversions.h" 196d528ed9Sopenharmony_ci#include "base/third_party/icu/icu_utf.h" 206d528ed9Sopenharmony_ci#include "base/values.h" 216d528ed9Sopenharmony_ci 226d528ed9Sopenharmony_cinamespace base { 236d528ed9Sopenharmony_cinamespace internal { 246d528ed9Sopenharmony_ci 256d528ed9Sopenharmony_cinamespace { 266d528ed9Sopenharmony_ci 276d528ed9Sopenharmony_ciconst int32_t kExtendedASCIIStart = 0x80; 286d528ed9Sopenharmony_ci 296d528ed9Sopenharmony_ci// Simple class that checks for maximum recursion/"stack overflow." 306d528ed9Sopenharmony_ciclass StackMarker { 316d528ed9Sopenharmony_ci public: 326d528ed9Sopenharmony_ci StackMarker(int max_depth, int* depth) 336d528ed9Sopenharmony_ci : max_depth_(max_depth), depth_(depth) { 346d528ed9Sopenharmony_ci ++(*depth_); 356d528ed9Sopenharmony_ci DCHECK_LE(*depth_, max_depth_); 366d528ed9Sopenharmony_ci } 376d528ed9Sopenharmony_ci ~StackMarker() { --(*depth_); } 386d528ed9Sopenharmony_ci 396d528ed9Sopenharmony_ci bool IsTooDeep() const { return *depth_ >= max_depth_; } 406d528ed9Sopenharmony_ci 416d528ed9Sopenharmony_ci private: 426d528ed9Sopenharmony_ci const int max_depth_; 436d528ed9Sopenharmony_ci int* const depth_; 446d528ed9Sopenharmony_ci 456d528ed9Sopenharmony_ci StackMarker(const StackMarker&) = delete; 466d528ed9Sopenharmony_ci StackMarker& operator=(const StackMarker&) = delete; 476d528ed9Sopenharmony_ci}; 486d528ed9Sopenharmony_ci 496d528ed9Sopenharmony_ciconstexpr uint32_t kUnicodeReplacementPoint = 0xFFFD; 506d528ed9Sopenharmony_ci 516d528ed9Sopenharmony_ci} // namespace 526d528ed9Sopenharmony_ci 536d528ed9Sopenharmony_ci// This is U+FFFD. 546d528ed9Sopenharmony_ciconst char kUnicodeReplacementString[] = "\xEF\xBF\xBD"; 556d528ed9Sopenharmony_ci 566d528ed9Sopenharmony_ciJSONParser::JSONParser(int options, int max_depth) 576d528ed9Sopenharmony_ci : options_(options), 586d528ed9Sopenharmony_ci max_depth_(max_depth), 596d528ed9Sopenharmony_ci index_(0), 606d528ed9Sopenharmony_ci stack_depth_(0), 616d528ed9Sopenharmony_ci line_number_(0), 626d528ed9Sopenharmony_ci index_last_line_(0), 636d528ed9Sopenharmony_ci error_code_(JSONReader::JSON_NO_ERROR), 646d528ed9Sopenharmony_ci error_line_(0), 656d528ed9Sopenharmony_ci error_column_(0) { 666d528ed9Sopenharmony_ci CHECK_LE(max_depth, JSONReader::kStackMaxDepth); 676d528ed9Sopenharmony_ci} 686d528ed9Sopenharmony_ci 696d528ed9Sopenharmony_ciJSONParser::~JSONParser() = default; 706d528ed9Sopenharmony_ci 716d528ed9Sopenharmony_cistd::optional<Value> JSONParser::Parse(std::string_view input) { 726d528ed9Sopenharmony_ci input_ = input; 736d528ed9Sopenharmony_ci index_ = 0; 746d528ed9Sopenharmony_ci line_number_ = 1; 756d528ed9Sopenharmony_ci index_last_line_ = 0; 766d528ed9Sopenharmony_ci 776d528ed9Sopenharmony_ci error_code_ = JSONReader::JSON_NO_ERROR; 786d528ed9Sopenharmony_ci error_line_ = 0; 796d528ed9Sopenharmony_ci error_column_ = 0; 806d528ed9Sopenharmony_ci 816d528ed9Sopenharmony_ci // ICU and ReadUnicodeCharacter() use int32_t for lengths, so ensure 826d528ed9Sopenharmony_ci // that the index_ will not overflow when parsing. 836d528ed9Sopenharmony_ci if (!base::IsValueInRangeForNumericType<int32_t>(input.length())) { 846d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_TOO_LARGE, 0); 856d528ed9Sopenharmony_ci return std::nullopt; 866d528ed9Sopenharmony_ci } 876d528ed9Sopenharmony_ci 886d528ed9Sopenharmony_ci // When the input JSON string starts with a UTF-8 Byte-Order-Mark, 896d528ed9Sopenharmony_ci // advance the start position to avoid the ParseNextToken function mis- 906d528ed9Sopenharmony_ci // treating a Unicode BOM as an invalid character and returning NULL. 916d528ed9Sopenharmony_ci ConsumeIfMatch("\xEF\xBB\xBF"); 926d528ed9Sopenharmony_ci 936d528ed9Sopenharmony_ci // Parse the first and any nested tokens. 946d528ed9Sopenharmony_ci std::optional<Value> root(ParseNextToken()); 956d528ed9Sopenharmony_ci if (!root) 966d528ed9Sopenharmony_ci return std::nullopt; 976d528ed9Sopenharmony_ci 986d528ed9Sopenharmony_ci // Make sure the input stream is at an end. 996d528ed9Sopenharmony_ci if (GetNextToken() != T_END_OF_INPUT) { 1006d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1); 1016d528ed9Sopenharmony_ci return std::nullopt; 1026d528ed9Sopenharmony_ci } 1036d528ed9Sopenharmony_ci 1046d528ed9Sopenharmony_ci return root; 1056d528ed9Sopenharmony_ci} 1066d528ed9Sopenharmony_ci 1076d528ed9Sopenharmony_ciJSONReader::JsonParseError JSONParser::error_code() const { 1086d528ed9Sopenharmony_ci return error_code_; 1096d528ed9Sopenharmony_ci} 1106d528ed9Sopenharmony_ci 1116d528ed9Sopenharmony_cistd::string JSONParser::GetErrorMessage() const { 1126d528ed9Sopenharmony_ci return FormatErrorMessage(error_line_, error_column_, 1136d528ed9Sopenharmony_ci JSONReader::ErrorCodeToString(error_code_)); 1146d528ed9Sopenharmony_ci} 1156d528ed9Sopenharmony_ci 1166d528ed9Sopenharmony_ciint JSONParser::error_line() const { 1176d528ed9Sopenharmony_ci return error_line_; 1186d528ed9Sopenharmony_ci} 1196d528ed9Sopenharmony_ci 1206d528ed9Sopenharmony_ciint JSONParser::error_column() const { 1216d528ed9Sopenharmony_ci return error_column_; 1226d528ed9Sopenharmony_ci} 1236d528ed9Sopenharmony_ci 1246d528ed9Sopenharmony_ci// StringBuilder /////////////////////////////////////////////////////////////// 1256d528ed9Sopenharmony_ci 1266d528ed9Sopenharmony_ciJSONParser::StringBuilder::StringBuilder() : StringBuilder(nullptr) {} 1276d528ed9Sopenharmony_ci 1286d528ed9Sopenharmony_ciJSONParser::StringBuilder::StringBuilder(const char* pos) 1296d528ed9Sopenharmony_ci : pos_(pos), length_(0) {} 1306d528ed9Sopenharmony_ci 1316d528ed9Sopenharmony_ciJSONParser::StringBuilder::~StringBuilder() = default; 1326d528ed9Sopenharmony_ci 1336d528ed9Sopenharmony_ciJSONParser::StringBuilder& JSONParser::StringBuilder::operator=( 1346d528ed9Sopenharmony_ci StringBuilder&& other) = default; 1356d528ed9Sopenharmony_ci 1366d528ed9Sopenharmony_civoid JSONParser::StringBuilder::Append(uint32_t point) { 1376d528ed9Sopenharmony_ci DCHECK(IsValidCharacter(point)); 1386d528ed9Sopenharmony_ci 1396d528ed9Sopenharmony_ci if (point < kExtendedASCIIStart && !string_) { 1406d528ed9Sopenharmony_ci DCHECK_EQ(static_cast<char>(point), pos_[length_]); 1416d528ed9Sopenharmony_ci ++length_; 1426d528ed9Sopenharmony_ci } else { 1436d528ed9Sopenharmony_ci Convert(); 1446d528ed9Sopenharmony_ci if (UNLIKELY(point == kUnicodeReplacementPoint)) { 1456d528ed9Sopenharmony_ci string_->append(kUnicodeReplacementString); 1466d528ed9Sopenharmony_ci } else { 1476d528ed9Sopenharmony_ci WriteUnicodeCharacter(point, &*string_); 1486d528ed9Sopenharmony_ci } 1496d528ed9Sopenharmony_ci } 1506d528ed9Sopenharmony_ci} 1516d528ed9Sopenharmony_ci 1526d528ed9Sopenharmony_civoid JSONParser::StringBuilder::Convert() { 1536d528ed9Sopenharmony_ci if (string_) 1546d528ed9Sopenharmony_ci return; 1556d528ed9Sopenharmony_ci string_.emplace(pos_, length_); 1566d528ed9Sopenharmony_ci} 1576d528ed9Sopenharmony_ci 1586d528ed9Sopenharmony_cistd::string JSONParser::StringBuilder::DestructiveAsString() { 1596d528ed9Sopenharmony_ci if (string_) 1606d528ed9Sopenharmony_ci return std::move(*string_); 1616d528ed9Sopenharmony_ci return std::string(pos_, length_); 1626d528ed9Sopenharmony_ci} 1636d528ed9Sopenharmony_ci 1646d528ed9Sopenharmony_ci// JSONParser private ////////////////////////////////////////////////////////// 1656d528ed9Sopenharmony_ci 1666d528ed9Sopenharmony_cistd::optional<std::string_view> JSONParser::PeekChars(int count) { 1676d528ed9Sopenharmony_ci if (static_cast<size_t>(index_) + count > input_.length()) 1686d528ed9Sopenharmony_ci return std::nullopt; 1696d528ed9Sopenharmony_ci // Using std::string_view::substr() is significantly slower (according to 1706d528ed9Sopenharmony_ci // base_perftests) than constructing a substring manually. 1716d528ed9Sopenharmony_ci return std::string_view(input_.data() + index_, count); 1726d528ed9Sopenharmony_ci} 1736d528ed9Sopenharmony_ci 1746d528ed9Sopenharmony_cistd::optional<char> JSONParser::PeekChar() { 1756d528ed9Sopenharmony_ci std::optional<std::string_view> chars = PeekChars(1); 1766d528ed9Sopenharmony_ci if (chars) 1776d528ed9Sopenharmony_ci return (*chars)[0]; 1786d528ed9Sopenharmony_ci return std::nullopt; 1796d528ed9Sopenharmony_ci} 1806d528ed9Sopenharmony_ci 1816d528ed9Sopenharmony_cistd::optional<std::string_view> JSONParser::ConsumeChars(int count) { 1826d528ed9Sopenharmony_ci std::optional<std::string_view> chars = PeekChars(count); 1836d528ed9Sopenharmony_ci if (chars) 1846d528ed9Sopenharmony_ci index_ += count; 1856d528ed9Sopenharmony_ci return chars; 1866d528ed9Sopenharmony_ci} 1876d528ed9Sopenharmony_ci 1886d528ed9Sopenharmony_cistd::optional<char> JSONParser::ConsumeChar() { 1896d528ed9Sopenharmony_ci std::optional<std::string_view> chars = ConsumeChars(1); 1906d528ed9Sopenharmony_ci if (chars) 1916d528ed9Sopenharmony_ci return (*chars)[0]; 1926d528ed9Sopenharmony_ci return std::nullopt; 1936d528ed9Sopenharmony_ci} 1946d528ed9Sopenharmony_ci 1956d528ed9Sopenharmony_ciconst char* JSONParser::pos() { 1966d528ed9Sopenharmony_ci CHECK_LE(static_cast<size_t>(index_), input_.length()); 1976d528ed9Sopenharmony_ci return input_.data() + index_; 1986d528ed9Sopenharmony_ci} 1996d528ed9Sopenharmony_ci 2006d528ed9Sopenharmony_ciJSONParser::Token JSONParser::GetNextToken() { 2016d528ed9Sopenharmony_ci EatWhitespaceAndComments(); 2026d528ed9Sopenharmony_ci 2036d528ed9Sopenharmony_ci std::optional<char> c = PeekChar(); 2046d528ed9Sopenharmony_ci if (!c) 2056d528ed9Sopenharmony_ci return T_END_OF_INPUT; 2066d528ed9Sopenharmony_ci 2076d528ed9Sopenharmony_ci switch (*c) { 2086d528ed9Sopenharmony_ci case '{': 2096d528ed9Sopenharmony_ci return T_OBJECT_BEGIN; 2106d528ed9Sopenharmony_ci case '}': 2116d528ed9Sopenharmony_ci return T_OBJECT_END; 2126d528ed9Sopenharmony_ci case '[': 2136d528ed9Sopenharmony_ci return T_ARRAY_BEGIN; 2146d528ed9Sopenharmony_ci case ']': 2156d528ed9Sopenharmony_ci return T_ARRAY_END; 2166d528ed9Sopenharmony_ci case '"': 2176d528ed9Sopenharmony_ci return T_STRING; 2186d528ed9Sopenharmony_ci case '0': 2196d528ed9Sopenharmony_ci case '1': 2206d528ed9Sopenharmony_ci case '2': 2216d528ed9Sopenharmony_ci case '3': 2226d528ed9Sopenharmony_ci case '4': 2236d528ed9Sopenharmony_ci case '5': 2246d528ed9Sopenharmony_ci case '6': 2256d528ed9Sopenharmony_ci case '7': 2266d528ed9Sopenharmony_ci case '8': 2276d528ed9Sopenharmony_ci case '9': 2286d528ed9Sopenharmony_ci case '-': 2296d528ed9Sopenharmony_ci return T_NUMBER; 2306d528ed9Sopenharmony_ci case 't': 2316d528ed9Sopenharmony_ci return T_BOOL_TRUE; 2326d528ed9Sopenharmony_ci case 'f': 2336d528ed9Sopenharmony_ci return T_BOOL_FALSE; 2346d528ed9Sopenharmony_ci case 'n': 2356d528ed9Sopenharmony_ci return T_NULL; 2366d528ed9Sopenharmony_ci case ',': 2376d528ed9Sopenharmony_ci return T_LIST_SEPARATOR; 2386d528ed9Sopenharmony_ci case ':': 2396d528ed9Sopenharmony_ci return T_OBJECT_PAIR_SEPARATOR; 2406d528ed9Sopenharmony_ci default: 2416d528ed9Sopenharmony_ci return T_INVALID_TOKEN; 2426d528ed9Sopenharmony_ci } 2436d528ed9Sopenharmony_ci} 2446d528ed9Sopenharmony_ci 2456d528ed9Sopenharmony_civoid JSONParser::EatWhitespaceAndComments() { 2466d528ed9Sopenharmony_ci while (std::optional<char> c = PeekChar()) { 2476d528ed9Sopenharmony_ci switch (*c) { 2486d528ed9Sopenharmony_ci case '\r': 2496d528ed9Sopenharmony_ci case '\n': 2506d528ed9Sopenharmony_ci index_last_line_ = index_; 2516d528ed9Sopenharmony_ci // Don't increment line_number_ twice for "\r\n". 2526d528ed9Sopenharmony_ci if (!(c == '\n' && index_ > 0 && input_[index_ - 1] == '\r')) { 2536d528ed9Sopenharmony_ci ++line_number_; 2546d528ed9Sopenharmony_ci } 2556d528ed9Sopenharmony_ci FALLTHROUGH; 2566d528ed9Sopenharmony_ci case ' ': 2576d528ed9Sopenharmony_ci case '\t': 2586d528ed9Sopenharmony_ci ConsumeChar(); 2596d528ed9Sopenharmony_ci break; 2606d528ed9Sopenharmony_ci case '/': 2616d528ed9Sopenharmony_ci if (!EatComment()) 2626d528ed9Sopenharmony_ci return; 2636d528ed9Sopenharmony_ci break; 2646d528ed9Sopenharmony_ci default: 2656d528ed9Sopenharmony_ci return; 2666d528ed9Sopenharmony_ci } 2676d528ed9Sopenharmony_ci } 2686d528ed9Sopenharmony_ci} 2696d528ed9Sopenharmony_ci 2706d528ed9Sopenharmony_cibool JSONParser::EatComment() { 2716d528ed9Sopenharmony_ci std::optional<std::string_view> comment_start = ConsumeChars(2); 2726d528ed9Sopenharmony_ci if (!comment_start) 2736d528ed9Sopenharmony_ci return false; 2746d528ed9Sopenharmony_ci 2756d528ed9Sopenharmony_ci if (comment_start == "//") { 2766d528ed9Sopenharmony_ci // Single line comment, read to newline. 2776d528ed9Sopenharmony_ci while (std::optional<char> c = PeekChar()) { 2786d528ed9Sopenharmony_ci if (c == '\n' || c == '\r') 2796d528ed9Sopenharmony_ci return true; 2806d528ed9Sopenharmony_ci ConsumeChar(); 2816d528ed9Sopenharmony_ci } 2826d528ed9Sopenharmony_ci } else if (comment_start == "/*") { 2836d528ed9Sopenharmony_ci char previous_char = '\0'; 2846d528ed9Sopenharmony_ci // Block comment, read until end marker. 2856d528ed9Sopenharmony_ci while (std::optional<char> c = PeekChar()) { 2866d528ed9Sopenharmony_ci if (previous_char == '*' && c == '/') { 2876d528ed9Sopenharmony_ci // EatWhitespaceAndComments will inspect pos(), which will still be on 2886d528ed9Sopenharmony_ci // the last / of the comment, so advance once more (which may also be 2896d528ed9Sopenharmony_ci // end of input). 2906d528ed9Sopenharmony_ci ConsumeChar(); 2916d528ed9Sopenharmony_ci return true; 2926d528ed9Sopenharmony_ci } 2936d528ed9Sopenharmony_ci previous_char = *ConsumeChar(); 2946d528ed9Sopenharmony_ci } 2956d528ed9Sopenharmony_ci 2966d528ed9Sopenharmony_ci // If the comment is unterminated, GetNextToken will report T_END_OF_INPUT. 2976d528ed9Sopenharmony_ci } 2986d528ed9Sopenharmony_ci 2996d528ed9Sopenharmony_ci return false; 3006d528ed9Sopenharmony_ci} 3016d528ed9Sopenharmony_ci 3026d528ed9Sopenharmony_cistd::optional<Value> JSONParser::ParseNextToken() { 3036d528ed9Sopenharmony_ci return ParseToken(GetNextToken()); 3046d528ed9Sopenharmony_ci} 3056d528ed9Sopenharmony_ci 3066d528ed9Sopenharmony_cistd::optional<Value> JSONParser::ParseToken(Token token) { 3076d528ed9Sopenharmony_ci switch (token) { 3086d528ed9Sopenharmony_ci case T_OBJECT_BEGIN: 3096d528ed9Sopenharmony_ci return ConsumeDictionary(); 3106d528ed9Sopenharmony_ci case T_ARRAY_BEGIN: 3116d528ed9Sopenharmony_ci return ConsumeList(); 3126d528ed9Sopenharmony_ci case T_STRING: 3136d528ed9Sopenharmony_ci return ConsumeString(); 3146d528ed9Sopenharmony_ci case T_NUMBER: 3156d528ed9Sopenharmony_ci return ConsumeNumber(); 3166d528ed9Sopenharmony_ci case T_BOOL_TRUE: 3176d528ed9Sopenharmony_ci case T_BOOL_FALSE: 3186d528ed9Sopenharmony_ci case T_NULL: 3196d528ed9Sopenharmony_ci return ConsumeLiteral(); 3206d528ed9Sopenharmony_ci default: 3216d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); 3226d528ed9Sopenharmony_ci return std::nullopt; 3236d528ed9Sopenharmony_ci } 3246d528ed9Sopenharmony_ci} 3256d528ed9Sopenharmony_ci 3266d528ed9Sopenharmony_cistd::optional<Value> JSONParser::ConsumeDictionary() { 3276d528ed9Sopenharmony_ci if (ConsumeChar() != '{') { 3286d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); 3296d528ed9Sopenharmony_ci return std::nullopt; 3306d528ed9Sopenharmony_ci } 3316d528ed9Sopenharmony_ci 3326d528ed9Sopenharmony_ci StackMarker depth_check(max_depth_, &stack_depth_); 3336d528ed9Sopenharmony_ci if (depth_check.IsTooDeep()) { 3346d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 0); 3356d528ed9Sopenharmony_ci return std::nullopt; 3366d528ed9Sopenharmony_ci } 3376d528ed9Sopenharmony_ci 3386d528ed9Sopenharmony_ci std::vector<Value::DictStorage::value_type> dict_storage; 3396d528ed9Sopenharmony_ci 3406d528ed9Sopenharmony_ci Token token = GetNextToken(); 3416d528ed9Sopenharmony_ci while (token != T_OBJECT_END) { 3426d528ed9Sopenharmony_ci if (token != T_STRING) { 3436d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1); 3446d528ed9Sopenharmony_ci return std::nullopt; 3456d528ed9Sopenharmony_ci } 3466d528ed9Sopenharmony_ci 3476d528ed9Sopenharmony_ci // First consume the key. 3486d528ed9Sopenharmony_ci StringBuilder key; 3496d528ed9Sopenharmony_ci if (!ConsumeStringRaw(&key)) { 3506d528ed9Sopenharmony_ci return std::nullopt; 3516d528ed9Sopenharmony_ci } 3526d528ed9Sopenharmony_ci 3536d528ed9Sopenharmony_ci // Read the separator. 3546d528ed9Sopenharmony_ci token = GetNextToken(); 3556d528ed9Sopenharmony_ci if (token != T_OBJECT_PAIR_SEPARATOR) { 3566d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); 3576d528ed9Sopenharmony_ci return std::nullopt; 3586d528ed9Sopenharmony_ci } 3596d528ed9Sopenharmony_ci 3606d528ed9Sopenharmony_ci // The next token is the value. Ownership transfers to |dict|. 3616d528ed9Sopenharmony_ci ConsumeChar(); 3626d528ed9Sopenharmony_ci std::optional<Value> value = ParseNextToken(); 3636d528ed9Sopenharmony_ci if (!value) { 3646d528ed9Sopenharmony_ci // ReportError from deeper level. 3656d528ed9Sopenharmony_ci return std::nullopt; 3666d528ed9Sopenharmony_ci } 3676d528ed9Sopenharmony_ci 3686d528ed9Sopenharmony_ci dict_storage.emplace_back(key.DestructiveAsString(), 3696d528ed9Sopenharmony_ci std::make_unique<Value>(std::move(*value))); 3706d528ed9Sopenharmony_ci 3716d528ed9Sopenharmony_ci token = GetNextToken(); 3726d528ed9Sopenharmony_ci if (token == T_LIST_SEPARATOR) { 3736d528ed9Sopenharmony_ci ConsumeChar(); 3746d528ed9Sopenharmony_ci token = GetNextToken(); 3756d528ed9Sopenharmony_ci if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { 3766d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_TRAILING_COMMA, 1); 3776d528ed9Sopenharmony_ci return std::nullopt; 3786d528ed9Sopenharmony_ci } 3796d528ed9Sopenharmony_ci } else if (token != T_OBJECT_END) { 3806d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); 3816d528ed9Sopenharmony_ci return std::nullopt; 3826d528ed9Sopenharmony_ci } 3836d528ed9Sopenharmony_ci } 3846d528ed9Sopenharmony_ci 3856d528ed9Sopenharmony_ci ConsumeChar(); // Closing '}'. 3866d528ed9Sopenharmony_ci 3876d528ed9Sopenharmony_ci return Value(Value::DictStorage(std::move(dict_storage), KEEP_LAST_OF_DUPES)); 3886d528ed9Sopenharmony_ci} 3896d528ed9Sopenharmony_ci 3906d528ed9Sopenharmony_cistd::optional<Value> JSONParser::ConsumeList() { 3916d528ed9Sopenharmony_ci if (ConsumeChar() != '[') { 3926d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); 3936d528ed9Sopenharmony_ci return std::nullopt; 3946d528ed9Sopenharmony_ci } 3956d528ed9Sopenharmony_ci 3966d528ed9Sopenharmony_ci StackMarker depth_check(max_depth_, &stack_depth_); 3976d528ed9Sopenharmony_ci if (depth_check.IsTooDeep()) { 3986d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 0); 3996d528ed9Sopenharmony_ci return std::nullopt; 4006d528ed9Sopenharmony_ci } 4016d528ed9Sopenharmony_ci 4026d528ed9Sopenharmony_ci Value::ListStorage list_storage; 4036d528ed9Sopenharmony_ci 4046d528ed9Sopenharmony_ci Token token = GetNextToken(); 4056d528ed9Sopenharmony_ci while (token != T_ARRAY_END) { 4066d528ed9Sopenharmony_ci std::optional<Value> item = ParseToken(token); 4076d528ed9Sopenharmony_ci if (!item) { 4086d528ed9Sopenharmony_ci // ReportError from deeper level. 4096d528ed9Sopenharmony_ci return std::nullopt; 4106d528ed9Sopenharmony_ci } 4116d528ed9Sopenharmony_ci 4126d528ed9Sopenharmony_ci list_storage.push_back(std::move(*item)); 4136d528ed9Sopenharmony_ci 4146d528ed9Sopenharmony_ci token = GetNextToken(); 4156d528ed9Sopenharmony_ci if (token == T_LIST_SEPARATOR) { 4166d528ed9Sopenharmony_ci ConsumeChar(); 4176d528ed9Sopenharmony_ci token = GetNextToken(); 4186d528ed9Sopenharmony_ci if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) { 4196d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_TRAILING_COMMA, 1); 4206d528ed9Sopenharmony_ci return std::nullopt; 4216d528ed9Sopenharmony_ci } 4226d528ed9Sopenharmony_ci } else if (token != T_ARRAY_END) { 4236d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); 4246d528ed9Sopenharmony_ci return std::nullopt; 4256d528ed9Sopenharmony_ci } 4266d528ed9Sopenharmony_ci } 4276d528ed9Sopenharmony_ci 4286d528ed9Sopenharmony_ci ConsumeChar(); // Closing ']'. 4296d528ed9Sopenharmony_ci 4306d528ed9Sopenharmony_ci return Value(std::move(list_storage)); 4316d528ed9Sopenharmony_ci} 4326d528ed9Sopenharmony_ci 4336d528ed9Sopenharmony_cistd::optional<Value> JSONParser::ConsumeString() { 4346d528ed9Sopenharmony_ci StringBuilder string; 4356d528ed9Sopenharmony_ci if (!ConsumeStringRaw(&string)) 4366d528ed9Sopenharmony_ci return std::nullopt; 4376d528ed9Sopenharmony_ci 4386d528ed9Sopenharmony_ci return Value(string.DestructiveAsString()); 4396d528ed9Sopenharmony_ci} 4406d528ed9Sopenharmony_ci 4416d528ed9Sopenharmony_cibool JSONParser::ConsumeStringRaw(StringBuilder* out) { 4426d528ed9Sopenharmony_ci if (ConsumeChar() != '"') { 4436d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1); 4446d528ed9Sopenharmony_ci return false; 4456d528ed9Sopenharmony_ci } 4466d528ed9Sopenharmony_ci 4476d528ed9Sopenharmony_ci // StringBuilder will internally build a std::string_view unless a UTF-16 4486d528ed9Sopenharmony_ci // conversion occurs, at which point it will perform a copy into a 4496d528ed9Sopenharmony_ci // std::string. 4506d528ed9Sopenharmony_ci StringBuilder string(pos()); 4516d528ed9Sopenharmony_ci 4526d528ed9Sopenharmony_ci while (PeekChar()) { 4536d528ed9Sopenharmony_ci uint32_t next_char = 0; 4546d528ed9Sopenharmony_ci if (!ReadUnicodeCharacter(input_.data(), 4556d528ed9Sopenharmony_ci static_cast<int32_t>(input_.length()), &index_, 4566d528ed9Sopenharmony_ci &next_char) || 4576d528ed9Sopenharmony_ci !IsValidCharacter(next_char)) { 4586d528ed9Sopenharmony_ci if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) { 4596d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 1); 4606d528ed9Sopenharmony_ci return false; 4616d528ed9Sopenharmony_ci } 4626d528ed9Sopenharmony_ci ConsumeChar(); 4636d528ed9Sopenharmony_ci string.Append(kUnicodeReplacementPoint); 4646d528ed9Sopenharmony_ci continue; 4656d528ed9Sopenharmony_ci } 4666d528ed9Sopenharmony_ci 4676d528ed9Sopenharmony_ci if (next_char == '"') { 4686d528ed9Sopenharmony_ci ConsumeChar(); 4696d528ed9Sopenharmony_ci *out = std::move(string); 4706d528ed9Sopenharmony_ci return true; 4716d528ed9Sopenharmony_ci } else if (next_char != '\\') { 4726d528ed9Sopenharmony_ci // If this character is not an escape sequence... 4736d528ed9Sopenharmony_ci ConsumeChar(); 4746d528ed9Sopenharmony_ci string.Append(next_char); 4756d528ed9Sopenharmony_ci } else { 4766d528ed9Sopenharmony_ci // And if it is an escape sequence, the input string will be adjusted 4776d528ed9Sopenharmony_ci // (either by combining the two characters of an encoded escape sequence, 4786d528ed9Sopenharmony_ci // or with a UTF conversion), so using std::string_view isn't possible -- 4796d528ed9Sopenharmony_ci // force a conversion. 4806d528ed9Sopenharmony_ci string.Convert(); 4816d528ed9Sopenharmony_ci 4826d528ed9Sopenharmony_ci // Read past the escape '\' and ensure there's a character following. 4836d528ed9Sopenharmony_ci std::optional<std::string_view> escape_sequence = ConsumeChars(2); 4846d528ed9Sopenharmony_ci if (!escape_sequence) { 4856d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); 4866d528ed9Sopenharmony_ci return false; 4876d528ed9Sopenharmony_ci } 4886d528ed9Sopenharmony_ci 4896d528ed9Sopenharmony_ci switch ((*escape_sequence)[1]) { 4906d528ed9Sopenharmony_ci // Allowed esape sequences: 4916d528ed9Sopenharmony_ci case 'x': { // UTF-8 sequence. 4926d528ed9Sopenharmony_ci // UTF-8 \x escape sequences are not allowed in the spec, but they 4936d528ed9Sopenharmony_ci // are supported here for backwards-compatiblity with the old parser. 4946d528ed9Sopenharmony_ci escape_sequence = ConsumeChars(2); 4956d528ed9Sopenharmony_ci if (!escape_sequence) { 4966d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_INVALID_ESCAPE, -2); 4976d528ed9Sopenharmony_ci return false; 4986d528ed9Sopenharmony_ci } 4996d528ed9Sopenharmony_ci 5006d528ed9Sopenharmony_ci int hex_digit = 0; 5016d528ed9Sopenharmony_ci if (!HexStringToInt(*escape_sequence, &hex_digit) || 5026d528ed9Sopenharmony_ci !IsValidCharacter(hex_digit)) { 5036d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_INVALID_ESCAPE, -2); 5046d528ed9Sopenharmony_ci return false; 5056d528ed9Sopenharmony_ci } 5066d528ed9Sopenharmony_ci 5076d528ed9Sopenharmony_ci string.Append(hex_digit); 5086d528ed9Sopenharmony_ci break; 5096d528ed9Sopenharmony_ci } 5106d528ed9Sopenharmony_ci case 'u': { // UTF-16 sequence. 5116d528ed9Sopenharmony_ci // UTF units are of the form \uXXXX. 5126d528ed9Sopenharmony_ci uint32_t code_point; 5136d528ed9Sopenharmony_ci if (!DecodeUTF16(&code_point)) { 5146d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); 5156d528ed9Sopenharmony_ci return false; 5166d528ed9Sopenharmony_ci } 5176d528ed9Sopenharmony_ci string.Append(code_point); 5186d528ed9Sopenharmony_ci break; 5196d528ed9Sopenharmony_ci } 5206d528ed9Sopenharmony_ci case '"': 5216d528ed9Sopenharmony_ci string.Append('"'); 5226d528ed9Sopenharmony_ci break; 5236d528ed9Sopenharmony_ci case '\\': 5246d528ed9Sopenharmony_ci string.Append('\\'); 5256d528ed9Sopenharmony_ci break; 5266d528ed9Sopenharmony_ci case '/': 5276d528ed9Sopenharmony_ci string.Append('/'); 5286d528ed9Sopenharmony_ci break; 5296d528ed9Sopenharmony_ci case 'b': 5306d528ed9Sopenharmony_ci string.Append('\b'); 5316d528ed9Sopenharmony_ci break; 5326d528ed9Sopenharmony_ci case 'f': 5336d528ed9Sopenharmony_ci string.Append('\f'); 5346d528ed9Sopenharmony_ci break; 5356d528ed9Sopenharmony_ci case 'n': 5366d528ed9Sopenharmony_ci string.Append('\n'); 5376d528ed9Sopenharmony_ci break; 5386d528ed9Sopenharmony_ci case 'r': 5396d528ed9Sopenharmony_ci string.Append('\r'); 5406d528ed9Sopenharmony_ci break; 5416d528ed9Sopenharmony_ci case 't': 5426d528ed9Sopenharmony_ci string.Append('\t'); 5436d528ed9Sopenharmony_ci break; 5446d528ed9Sopenharmony_ci case 'v': // Not listed as valid escape sequence in the RFC. 5456d528ed9Sopenharmony_ci string.Append('\v'); 5466d528ed9Sopenharmony_ci break; 5476d528ed9Sopenharmony_ci // All other escape squences are illegal. 5486d528ed9Sopenharmony_ci default: 5496d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_INVALID_ESCAPE, 0); 5506d528ed9Sopenharmony_ci return false; 5516d528ed9Sopenharmony_ci } 5526d528ed9Sopenharmony_ci } 5536d528ed9Sopenharmony_ci } 5546d528ed9Sopenharmony_ci 5556d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 0); 5566d528ed9Sopenharmony_ci return false; 5576d528ed9Sopenharmony_ci} 5586d528ed9Sopenharmony_ci 5596d528ed9Sopenharmony_ci// Entry is at the first X in \uXXXX. 5606d528ed9Sopenharmony_cibool JSONParser::DecodeUTF16(uint32_t* out_code_point) { 5616d528ed9Sopenharmony_ci std::optional<std::string_view> escape_sequence = ConsumeChars(4); 5626d528ed9Sopenharmony_ci if (!escape_sequence) 5636d528ed9Sopenharmony_ci return false; 5646d528ed9Sopenharmony_ci 5656d528ed9Sopenharmony_ci // Consume the UTF-16 code unit, which may be a high surrogate. 5666d528ed9Sopenharmony_ci int code_unit16_high = 0; 5676d528ed9Sopenharmony_ci if (!HexStringToInt(*escape_sequence, &code_unit16_high)) 5686d528ed9Sopenharmony_ci return false; 5696d528ed9Sopenharmony_ci 5706d528ed9Sopenharmony_ci // If this is a high surrogate, consume the next code unit to get the 5716d528ed9Sopenharmony_ci // low surrogate. 5726d528ed9Sopenharmony_ci if (CBU16_IS_SURROGATE(code_unit16_high)) { 5736d528ed9Sopenharmony_ci // Make sure this is the high surrogate. If not, it's an encoding 5746d528ed9Sopenharmony_ci // error. 5756d528ed9Sopenharmony_ci if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high)) 5766d528ed9Sopenharmony_ci return false; 5776d528ed9Sopenharmony_ci 5786d528ed9Sopenharmony_ci // Make sure that the token has more characters to consume the 5796d528ed9Sopenharmony_ci // lower surrogate. 5806d528ed9Sopenharmony_ci if (!ConsumeIfMatch("\\u")) 5816d528ed9Sopenharmony_ci return false; 5826d528ed9Sopenharmony_ci 5836d528ed9Sopenharmony_ci escape_sequence = ConsumeChars(4); 5846d528ed9Sopenharmony_ci if (!escape_sequence) 5856d528ed9Sopenharmony_ci return false; 5866d528ed9Sopenharmony_ci 5876d528ed9Sopenharmony_ci int code_unit16_low = 0; 5886d528ed9Sopenharmony_ci if (!HexStringToInt(*escape_sequence, &code_unit16_low)) 5896d528ed9Sopenharmony_ci return false; 5906d528ed9Sopenharmony_ci 5916d528ed9Sopenharmony_ci if (!CBU16_IS_TRAIL(code_unit16_low)) 5926d528ed9Sopenharmony_ci return false; 5936d528ed9Sopenharmony_ci 5946d528ed9Sopenharmony_ci uint32_t code_point = 5956d528ed9Sopenharmony_ci CBU16_GET_SUPPLEMENTARY(code_unit16_high, code_unit16_low); 5966d528ed9Sopenharmony_ci if (!IsValidCharacter(code_point)) 5976d528ed9Sopenharmony_ci return false; 5986d528ed9Sopenharmony_ci 5996d528ed9Sopenharmony_ci *out_code_point = code_point; 6006d528ed9Sopenharmony_ci } else { 6016d528ed9Sopenharmony_ci // Not a surrogate. 6026d528ed9Sopenharmony_ci DCHECK(CBU16_IS_SINGLE(code_unit16_high)); 6036d528ed9Sopenharmony_ci if (!IsValidCharacter(code_unit16_high)) { 6046d528ed9Sopenharmony_ci if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) { 6056d528ed9Sopenharmony_ci return false; 6066d528ed9Sopenharmony_ci } 6076d528ed9Sopenharmony_ci *out_code_point = kUnicodeReplacementPoint; 6086d528ed9Sopenharmony_ci return true; 6096d528ed9Sopenharmony_ci } 6106d528ed9Sopenharmony_ci 6116d528ed9Sopenharmony_ci *out_code_point = code_unit16_high; 6126d528ed9Sopenharmony_ci } 6136d528ed9Sopenharmony_ci 6146d528ed9Sopenharmony_ci return true; 6156d528ed9Sopenharmony_ci} 6166d528ed9Sopenharmony_ci 6176d528ed9Sopenharmony_cistd::optional<Value> JSONParser::ConsumeNumber() { 6186d528ed9Sopenharmony_ci const char* num_start = pos(); 6196d528ed9Sopenharmony_ci const int start_index = index_; 6206d528ed9Sopenharmony_ci int end_index = start_index; 6216d528ed9Sopenharmony_ci 6226d528ed9Sopenharmony_ci if (PeekChar() == '-') 6236d528ed9Sopenharmony_ci ConsumeChar(); 6246d528ed9Sopenharmony_ci 6256d528ed9Sopenharmony_ci if (!ReadInt(false)) { 6266d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); 6276d528ed9Sopenharmony_ci return std::nullopt; 6286d528ed9Sopenharmony_ci } 6296d528ed9Sopenharmony_ci end_index = index_; 6306d528ed9Sopenharmony_ci 6316d528ed9Sopenharmony_ci // The optional fraction part. 6326d528ed9Sopenharmony_ci if (PeekChar() == '.') { 6336d528ed9Sopenharmony_ci ConsumeChar(); 6346d528ed9Sopenharmony_ci if (!ReadInt(true)) { 6356d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); 6366d528ed9Sopenharmony_ci return std::nullopt; 6376d528ed9Sopenharmony_ci } 6386d528ed9Sopenharmony_ci end_index = index_; 6396d528ed9Sopenharmony_ci } 6406d528ed9Sopenharmony_ci 6416d528ed9Sopenharmony_ci // Optional exponent part. 6426d528ed9Sopenharmony_ci std::optional<char> c = PeekChar(); 6436d528ed9Sopenharmony_ci if (c == 'e' || c == 'E') { 6446d528ed9Sopenharmony_ci ConsumeChar(); 6456d528ed9Sopenharmony_ci if (PeekChar() == '-' || PeekChar() == '+') { 6466d528ed9Sopenharmony_ci ConsumeChar(); 6476d528ed9Sopenharmony_ci } 6486d528ed9Sopenharmony_ci if (!ReadInt(true)) { 6496d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); 6506d528ed9Sopenharmony_ci return std::nullopt; 6516d528ed9Sopenharmony_ci } 6526d528ed9Sopenharmony_ci end_index = index_; 6536d528ed9Sopenharmony_ci } 6546d528ed9Sopenharmony_ci 6556d528ed9Sopenharmony_ci // ReadInt is greedy because numbers have no easily detectable sentinel, 6566d528ed9Sopenharmony_ci // so save off where the parser should be on exit (see Consume invariant at 6576d528ed9Sopenharmony_ci // the top of the header), then make sure the next token is one which is 6586d528ed9Sopenharmony_ci // valid. 6596d528ed9Sopenharmony_ci int exit_index = index_; 6606d528ed9Sopenharmony_ci 6616d528ed9Sopenharmony_ci switch (GetNextToken()) { 6626d528ed9Sopenharmony_ci case T_OBJECT_END: 6636d528ed9Sopenharmony_ci case T_ARRAY_END: 6646d528ed9Sopenharmony_ci case T_LIST_SEPARATOR: 6656d528ed9Sopenharmony_ci case T_END_OF_INPUT: 6666d528ed9Sopenharmony_ci break; 6676d528ed9Sopenharmony_ci default: 6686d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); 6696d528ed9Sopenharmony_ci return std::nullopt; 6706d528ed9Sopenharmony_ci } 6716d528ed9Sopenharmony_ci 6726d528ed9Sopenharmony_ci index_ = exit_index; 6736d528ed9Sopenharmony_ci 6746d528ed9Sopenharmony_ci std::string_view num_string(num_start, end_index - start_index); 6756d528ed9Sopenharmony_ci 6766d528ed9Sopenharmony_ci int num_int; 6776d528ed9Sopenharmony_ci if (StringToInt(num_string, &num_int)) 6786d528ed9Sopenharmony_ci return Value(num_int); 6796d528ed9Sopenharmony_ci 6806d528ed9Sopenharmony_ci return std::nullopt; 6816d528ed9Sopenharmony_ci} 6826d528ed9Sopenharmony_ci 6836d528ed9Sopenharmony_cibool JSONParser::ReadInt(bool allow_leading_zeros) { 6846d528ed9Sopenharmony_ci size_t len = 0; 6856d528ed9Sopenharmony_ci char first = 0; 6866d528ed9Sopenharmony_ci 6876d528ed9Sopenharmony_ci while (std::optional<char> c = PeekChar()) { 6886d528ed9Sopenharmony_ci if (!IsAsciiDigit(c)) 6896d528ed9Sopenharmony_ci break; 6906d528ed9Sopenharmony_ci 6916d528ed9Sopenharmony_ci if (len == 0) 6926d528ed9Sopenharmony_ci first = *c; 6936d528ed9Sopenharmony_ci 6946d528ed9Sopenharmony_ci ++len; 6956d528ed9Sopenharmony_ci ConsumeChar(); 6966d528ed9Sopenharmony_ci } 6976d528ed9Sopenharmony_ci 6986d528ed9Sopenharmony_ci if (len == 0) 6996d528ed9Sopenharmony_ci return false; 7006d528ed9Sopenharmony_ci 7016d528ed9Sopenharmony_ci if (!allow_leading_zeros && len > 1 && first == '0') 7026d528ed9Sopenharmony_ci return false; 7036d528ed9Sopenharmony_ci 7046d528ed9Sopenharmony_ci return true; 7056d528ed9Sopenharmony_ci} 7066d528ed9Sopenharmony_ci 7076d528ed9Sopenharmony_cistd::optional<Value> JSONParser::ConsumeLiteral() { 7086d528ed9Sopenharmony_ci if (ConsumeIfMatch("true")) { 7096d528ed9Sopenharmony_ci return Value(true); 7106d528ed9Sopenharmony_ci } else if (ConsumeIfMatch("false")) { 7116d528ed9Sopenharmony_ci return Value(false); 7126d528ed9Sopenharmony_ci } else if (ConsumeIfMatch("null")) { 7136d528ed9Sopenharmony_ci return Value(Value::Type::NONE); 7146d528ed9Sopenharmony_ci } else { 7156d528ed9Sopenharmony_ci ReportError(JSONReader::JSON_SYNTAX_ERROR, 1); 7166d528ed9Sopenharmony_ci return std::nullopt; 7176d528ed9Sopenharmony_ci } 7186d528ed9Sopenharmony_ci} 7196d528ed9Sopenharmony_ci 7206d528ed9Sopenharmony_cibool JSONParser::ConsumeIfMatch(std::string_view match) { 7216d528ed9Sopenharmony_ci if (match == PeekChars(match.size())) { 7226d528ed9Sopenharmony_ci ConsumeChars(match.size()); 7236d528ed9Sopenharmony_ci return true; 7246d528ed9Sopenharmony_ci } 7256d528ed9Sopenharmony_ci return false; 7266d528ed9Sopenharmony_ci} 7276d528ed9Sopenharmony_ci 7286d528ed9Sopenharmony_civoid JSONParser::ReportError(JSONReader::JsonParseError code, 7296d528ed9Sopenharmony_ci int column_adjust) { 7306d528ed9Sopenharmony_ci error_code_ = code; 7316d528ed9Sopenharmony_ci error_line_ = line_number_; 7326d528ed9Sopenharmony_ci error_column_ = index_ - index_last_line_ + column_adjust; 7336d528ed9Sopenharmony_ci} 7346d528ed9Sopenharmony_ci 7356d528ed9Sopenharmony_ci// static 7366d528ed9Sopenharmony_cistd::string JSONParser::FormatErrorMessage(int line, 7376d528ed9Sopenharmony_ci int column, 7386d528ed9Sopenharmony_ci const std::string& description) { 7396d528ed9Sopenharmony_ci if (line || column) { 7406d528ed9Sopenharmony_ci return StringPrintf("Line: %i, column: %i, %s", line, column, 7416d528ed9Sopenharmony_ci description.c_str()); 7426d528ed9Sopenharmony_ci } 7436d528ed9Sopenharmony_ci return description; 7446d528ed9Sopenharmony_ci} 7456d528ed9Sopenharmony_ci 7466d528ed9Sopenharmony_ci} // namespace internal 7476d528ed9Sopenharmony_ci} // namespace base 748