summaryrefslogtreecommitdiff
path: root/chromium/base/json
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/json')
-rw-r--r--chromium/base/json/json_common.h2
-rw-r--r--chromium/base/json/json_file_value_serializer.h2
-rw-r--r--chromium/base/json/json_parser.cc129
-rw-r--r--chromium/base/json/json_parser.h38
-rw-r--r--chromium/base/json/json_parser_unittest.cc161
-rw-r--r--chromium/base/json/json_perftest_decodebench.cc1
-rw-r--r--chromium/base/json/json_reader.cc94
-rw-r--r--chromium/base/json/json_reader.h73
-rw-r--r--chromium/base/json/json_reader_fuzzer.cc2
-rw-r--r--chromium/base/json/json_reader_unittest.cc52
-rw-r--r--chromium/base/json/json_string_value_serializer.cc12
-rw-r--r--chromium/base/json/json_value_serializer_unittest.cc14
12 files changed, 282 insertions, 298 deletions
diff --git a/chromium/base/json/json_common.h b/chromium/base/json/json_common.h
index c0fd3eab82b..f98fb00455f 100644
--- a/chromium/base/json/json_common.h
+++ b/chromium/base/json/json_common.h
@@ -7,7 +7,7 @@
#include <stddef.h>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/macros.h"
namespace base {
diff --git a/chromium/base/json/json_file_value_serializer.h b/chromium/base/json/json_file_value_serializer.h
index a93950a6080..f38cec24cf7 100644
--- a/chromium/base/json/json_file_value_serializer.h
+++ b/chromium/base/json/json_file_value_serializer.h
@@ -67,7 +67,7 @@ class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer {
// This enum is designed to safely overlap with JSONReader::JsonParseError.
enum JsonFileError {
JSON_NO_ERROR = 0,
- JSON_ACCESS_DENIED = 1000,
+ JSON_ACCESS_DENIED = kErrorCodeFirstMetadataError,
JSON_CANNOT_READ_FILE,
JSON_FILE_LOCKED,
JSON_NO_SUCH_FILE
diff --git a/chromium/base/json/json_parser.cc b/chromium/base/json/json_parser.cc
index e1e44c9781f..fcb479ceabd 100644
--- a/chromium/base/json/json_parser.cc
+++ b/chromium/base/json/json_parser.cc
@@ -9,7 +9,9 @@
#include <vector>
#include "base/check_op.h"
+#include "base/json/json_reader.h"
#include "base/macros.h"
+#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -18,13 +20,47 @@
#include "base/strings/utf_string_conversion_utils.h"
#include "base/strings/utf_string_conversions.h"
#include "base/third_party/icu/icu_utf.h"
-#include "base/values.h"
namespace base {
namespace internal {
namespace {
+// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
+static_assert(JSONParser::JSON_PARSE_ERROR_COUNT < 1000,
+ "JSONParser error out of bounds");
+
+std::string ErrorCodeToString(JSONParser::JsonParseError error_code) {
+ switch (error_code) {
+ case JSONParser::JSON_NO_ERROR:
+ return std::string();
+ case JSONParser::JSON_SYNTAX_ERROR:
+ return JSONParser::kSyntaxError;
+ case JSONParser::JSON_INVALID_ESCAPE:
+ return JSONParser::kInvalidEscape;
+ case JSONParser::JSON_UNEXPECTED_TOKEN:
+ return JSONParser::kUnexpectedToken;
+ case JSONParser::JSON_TRAILING_COMMA:
+ return JSONParser::kTrailingComma;
+ case JSONParser::JSON_TOO_MUCH_NESTING:
+ return JSONParser::kTooMuchNesting;
+ case JSONParser::JSON_UNEXPECTED_DATA_AFTER_ROOT:
+ return JSONParser::kUnexpectedDataAfterRoot;
+ case JSONParser::JSON_UNSUPPORTED_ENCODING:
+ return JSONParser::kUnsupportedEncoding;
+ case JSONParser::JSON_UNQUOTED_DICTIONARY_KEY:
+ return JSONParser::kUnquotedDictionaryKey;
+ case JSONParser::JSON_TOO_LARGE:
+ return JSONParser::kInputTooLarge;
+ case JSONParser::JSON_UNREPRESENTABLE_NUMBER:
+ return JSONParser::kUnrepresentableNumber;
+ case JSONParser::JSON_PARSE_ERROR_COUNT:
+ break;
+ }
+ NOTREACHED();
+ return std::string();
+}
+
const int32_t kExtendedASCIIStart = 0x80;
constexpr uint32_t kUnicodeReplacementPoint = 0xFFFD;
@@ -45,6 +81,21 @@ bool UnprefixedHexStringToInt(StringPiece input, int* output) {
// This is U+FFFD.
const char kUnicodeReplacementString[] = "\xEF\xBF\xBD";
+const char JSONParser::kSyntaxError[] = "Syntax error.";
+const char JSONParser::kInvalidEscape[] = "Invalid escape sequence.";
+const char JSONParser::kUnexpectedToken[] = "Unexpected token.";
+const char JSONParser::kTrailingComma[] = "Trailing comma not allowed.";
+const char JSONParser::kTooMuchNesting[] = "Too much nesting.";
+const char JSONParser::kUnexpectedDataAfterRoot[] =
+ "Unexpected data after root element.";
+const char JSONParser::kUnsupportedEncoding[] =
+ "Unsupported encoding. JSON must be UTF-8.";
+const char JSONParser::kUnquotedDictionaryKey[] =
+ "Dictionary keys must be quoted.";
+const char JSONParser::kInputTooLarge[] = "Input string is too large (>2GB).";
+const char JSONParser::kUnrepresentableNumber[] =
+ "Number cannot be represented.";
+
JSONParser::JSONParser(int options, size_t max_depth)
: options_(options),
max_depth_(max_depth),
@@ -52,7 +103,7 @@ JSONParser::JSONParser(int options, size_t max_depth)
stack_depth_(0),
line_number_(0),
index_last_line_(0),
- error_code_(JSONReader::JSON_NO_ERROR),
+ error_code_(JSON_NO_ERROR),
error_line_(0),
error_column_(0) {
CHECK_LE(max_depth, kAbsoluteMaxDepth);
@@ -77,14 +128,14 @@ Optional<Value> JSONParser::Parse(StringPiece input) {
line_number_ = 1;
index_last_line_ = -1;
- error_code_ = JSONReader::JSON_NO_ERROR;
+ error_code_ = JSON_NO_ERROR;
error_line_ = 0;
error_column_ = 0;
// ICU and ReadUnicodeCharacter() use int32_t for lengths, so ensure
// that the index_ will not overflow when parsing.
if (!base::IsValueInRangeForNumericType<int32_t>(input.length())) {
- ReportError(JSONReader::JSON_TOO_LARGE, -1);
+ ReportError(JSON_TOO_LARGE, -1);
return nullopt;
}
@@ -100,20 +151,20 @@ Optional<Value> JSONParser::Parse(StringPiece input) {
// Make sure the input stream is at an end.
if (GetNextToken() != T_END_OF_INPUT) {
- ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 0);
+ ReportError(JSON_UNEXPECTED_DATA_AFTER_ROOT, 0);
return nullopt;
}
return root;
}
-JSONReader::JsonParseError JSONParser::error_code() const {
+JSONParser::JsonParseError JSONParser::error_code() const {
return error_code_;
}
std::string JSONParser::GetErrorMessage() const {
return FormatErrorMessage(error_line_, error_column_,
- JSONReader::ErrorCodeToString(error_code_));
+ ErrorCodeToString(error_code_));
}
int JSONParser::error_line() const {
@@ -323,20 +374,20 @@ Optional<Value> JSONParser::ParseToken(Token token) {
case T_NULL:
return ConsumeLiteral();
default:
- ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 0);
+ ReportError(JSON_UNEXPECTED_TOKEN, 0);
return nullopt;
}
}
Optional<Value> JSONParser::ConsumeDictionary() {
if (ConsumeChar() != '{') {
- ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 0);
+ ReportError(JSON_UNEXPECTED_TOKEN, 0);
return nullopt;
}
StackMarker depth_check(max_depth_, &stack_depth_);
if (depth_check.IsTooDeep()) {
- ReportError(JSONReader::JSON_TOO_MUCH_NESTING, -1);
+ ReportError(JSON_TOO_MUCH_NESTING, -1);
return nullopt;
}
@@ -345,7 +396,7 @@ Optional<Value> JSONParser::ConsumeDictionary() {
Token token = GetNextToken();
while (token != T_OBJECT_END) {
if (token != T_STRING) {
- ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 0);
+ ReportError(JSON_UNQUOTED_DICTIONARY_KEY, 0);
return nullopt;
}
@@ -358,7 +409,7 @@ Optional<Value> JSONParser::ConsumeDictionary() {
// Read the separator.
token = GetNextToken();
if (token != T_OBJECT_PAIR_SEPARATOR) {
- ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+ ReportError(JSON_SYNTAX_ERROR, 0);
return nullopt;
}
@@ -378,11 +429,11 @@ Optional<Value> JSONParser::ConsumeDictionary() {
ConsumeChar();
token = GetNextToken();
if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
- ReportError(JSONReader::JSON_TRAILING_COMMA, 0);
+ ReportError(JSON_TRAILING_COMMA, 0);
return nullopt;
}
} else if (token != T_OBJECT_END) {
- ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+ ReportError(JSON_SYNTAX_ERROR, 0);
return nullopt;
}
}
@@ -396,13 +447,13 @@ Optional<Value> JSONParser::ConsumeDictionary() {
Optional<Value> JSONParser::ConsumeList() {
if (ConsumeChar() != '[') {
- ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 0);
+ ReportError(JSON_UNEXPECTED_TOKEN, 0);
return nullopt;
}
StackMarker depth_check(max_depth_, &stack_depth_);
if (depth_check.IsTooDeep()) {
- ReportError(JSONReader::JSON_TOO_MUCH_NESTING, -1);
+ ReportError(JSON_TOO_MUCH_NESTING, -1);
return nullopt;
}
@@ -423,11 +474,11 @@ Optional<Value> JSONParser::ConsumeList() {
ConsumeChar();
token = GetNextToken();
if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
- ReportError(JSONReader::JSON_TRAILING_COMMA, 0);
+ ReportError(JSON_TRAILING_COMMA, 0);
return nullopt;
}
} else if (token != T_ARRAY_END) {
- ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+ ReportError(JSON_SYNTAX_ERROR, 0);
return nullopt;
}
}
@@ -446,7 +497,7 @@ Optional<Value> JSONParser::ConsumeString() {
bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
if (ConsumeChar() != '"') {
- ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 0);
+ ReportError(JSON_UNEXPECTED_TOKEN, 0);
return false;
}
@@ -462,7 +513,7 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
&next_char) ||
!IsValidCodepoint(next_char)) {
if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0) {
- ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 0);
+ ReportError(JSON_UNSUPPORTED_ENCODING, 0);
return false;
}
ConsumeChar();
@@ -501,7 +552,7 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
// Read past the escape '\' and ensure there's a character following.
Optional<StringPiece> escape_sequence = ConsumeChars(2);
if (!escape_sequence) {
- ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+ ReportError(JSON_INVALID_ESCAPE, -1);
return false;
}
@@ -512,14 +563,14 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
// are supported here for backwards-compatiblity with the old parser.
escape_sequence = ConsumeChars(2);
if (!escape_sequence) {
- ReportError(JSONReader::JSON_INVALID_ESCAPE, -3);
+ ReportError(JSON_INVALID_ESCAPE, -3);
return false;
}
int hex_digit = 0;
if (!UnprefixedHexStringToInt(*escape_sequence, &hex_digit) ||
!IsValidCharacter(hex_digit)) {
- ReportError(JSONReader::JSON_INVALID_ESCAPE, -3);
+ ReportError(JSON_INVALID_ESCAPE, -3);
return false;
}
@@ -530,7 +581,7 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
// UTF units are of the form \uXXXX.
uint32_t code_point;
if (!DecodeUTF16(&code_point)) {
- ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+ ReportError(JSON_INVALID_ESCAPE, -1);
return false;
}
string.Append(code_point);
@@ -565,13 +616,13 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
break;
// All other escape squences are illegal.
default:
- ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+ ReportError(JSON_INVALID_ESCAPE, -1);
return false;
}
}
}
- ReportError(JSONReader::JSON_SYNTAX_ERROR, -1);
+ ReportError(JSON_SYNTAX_ERROR, -1);
return false;
}
@@ -589,10 +640,13 @@ bool JSONParser::DecodeUTF16(uint32_t* out_code_point) {
// If this is a high surrogate, consume the next code unit to get the
// low surrogate.
if (CBU16_IS_SURROGATE(code_unit16_high)) {
- // Make sure this is the high surrogate. If not, it's an encoding
- // error.
- if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high))
- return false;
+ // Make sure this is the high surrogate.
+ if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high)) {
+ if ((options_ & JSON_REPLACE_INVALID_CHARACTERS) == 0)
+ return false;
+ *out_code_point = kUnicodeReplacementPoint;
+ return true;
+ }
// Make sure that the token has more characters to consume the
// lower surrogate.
@@ -641,7 +695,7 @@ Optional<Value> JSONParser::ConsumeNumber() {
ConsumeChar();
if (!ReadInt(false)) {
- ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+ ReportError(JSON_SYNTAX_ERROR, 0);
return nullopt;
}
end_index = index_;
@@ -650,7 +704,7 @@ Optional<Value> JSONParser::ConsumeNumber() {
if (PeekChar() == '.') {
ConsumeChar();
if (!ReadInt(true)) {
- ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+ ReportError(JSON_SYNTAX_ERROR, 0);
return nullopt;
}
end_index = index_;
@@ -664,7 +718,7 @@ Optional<Value> JSONParser::ConsumeNumber() {
ConsumeChar();
}
if (!ReadInt(true)) {
- ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+ ReportError(JSON_SYNTAX_ERROR, 0);
return nullopt;
}
end_index = index_;
@@ -683,7 +737,7 @@ Optional<Value> JSONParser::ConsumeNumber() {
case T_END_OF_INPUT:
break;
default:
- ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+ ReportError(JSON_SYNTAX_ERROR, 0);
return nullopt;
}
@@ -701,7 +755,7 @@ Optional<Value> JSONParser::ConsumeNumber() {
return Value(num_double);
}
- ReportError(JSONReader::JSON_UNREPRESENTABLE_NUMBER, 0);
+ ReportError(JSON_UNREPRESENTABLE_NUMBER, 0);
return nullopt;
}
@@ -736,7 +790,7 @@ Optional<Value> JSONParser::ConsumeLiteral() {
return Value(false);
if (ConsumeIfMatch("null"))
return Value(Value::Type::NONE);
- ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+ ReportError(JSON_SYNTAX_ERROR, 0);
return nullopt;
}
@@ -748,8 +802,7 @@ bool JSONParser::ConsumeIfMatch(StringPiece match) {
return false;
}
-void JSONParser::ReportError(JSONReader::JsonParseError code,
- int column_adjust) {
+void JSONParser::ReportError(JsonParseError code, int column_adjust) {
error_code_ = code;
error_line_ = line_number_;
error_column_ = index_ - index_last_line_ + column_adjust;
diff --git a/chromium/base/json/json_parser.h b/chromium/base/json/json_parser.h
index 523062e6812..1481a8d2ba7 100644
--- a/chromium/base/json/json_parser.h
+++ b/chromium/base/json/json_parser.h
@@ -15,10 +15,10 @@
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/json/json_common.h"
-#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
+#include "base/values.h"
namespace base {
@@ -44,7 +44,35 @@ class JSONParserTest;
// of the next token.
class BASE_EXPORT JSONParser {
public:
- JSONParser(int options, size_t max_depth = kAbsoluteMaxDepth);
+ // Error codes during parsing.
+ enum JsonParseError {
+ JSON_NO_ERROR = base::ValueDeserializer::kErrorCodeNoError,
+ JSON_SYNTAX_ERROR = base::ValueDeserializer::kErrorCodeInvalidFormat,
+ JSON_INVALID_ESCAPE,
+ JSON_UNEXPECTED_TOKEN,
+ JSON_TRAILING_COMMA,
+ JSON_TOO_MUCH_NESTING,
+ JSON_UNEXPECTED_DATA_AFTER_ROOT,
+ JSON_UNSUPPORTED_ENCODING,
+ JSON_UNQUOTED_DICTIONARY_KEY,
+ JSON_TOO_LARGE,
+ JSON_UNREPRESENTABLE_NUMBER,
+ JSON_PARSE_ERROR_COUNT
+ };
+
+ // String versions of parse error codes.
+ static const char kSyntaxError[];
+ static const char kInvalidEscape[];
+ static const char kUnexpectedToken[];
+ static const char kTrailingComma[];
+ static const char kTooMuchNesting[];
+ static const char kUnexpectedDataAfterRoot[];
+ static const char kUnsupportedEncoding[];
+ static const char kUnquotedDictionaryKey[];
+ static const char kInputTooLarge[];
+ static const char kUnrepresentableNumber[];
+
+ explicit JSONParser(int options, size_t max_depth = kAbsoluteMaxDepth);
~JSONParser();
// Parses the input string according to the set options and returns the
@@ -54,7 +82,7 @@ class BASE_EXPORT JSONParser {
Optional<Value> Parse(StringPiece input);
// Returns the error code.
- JSONReader::JsonParseError error_code() const;
+ JsonParseError error_code() const;
// Returns the human-friendly error message.
std::string GetErrorMessage() const;
@@ -205,7 +233,7 @@ class BASE_EXPORT JSONParser {
// Sets the error information to |code| at the current column, based on
// |index_| and |index_last_line_|, with an optional positive/negative
// adjustment by |column_adjust|.
- void ReportError(JSONReader::JsonParseError code, int column_adjust);
+ void ReportError(JsonParseError code, int column_adjust);
// Given the line and column number of an error, formats one of the error
// message contants from json_reader.h for human display.
@@ -234,7 +262,7 @@ class BASE_EXPORT JSONParser {
int index_last_line_;
// Error information.
- JSONReader::JsonParseError error_code_;
+ JsonParseError error_code_;
int error_line_;
int error_column_;
diff --git a/chromium/base/json/json_parser_unittest.cc b/chromium/base/json/json_parser_unittest.cc
index c4926423433..9e89afe3f7d 100644
--- a/chromium/base/json/json_parser_unittest.cc
+++ b/chromium/base/json/json_parser_unittest.cc
@@ -210,76 +210,103 @@ TEST_F(JSONParserTest, ConsumeNumbers) {
}
TEST_F(JSONParserTest, ErrorMessages) {
- JSONReader::ValueWithError root =
- JSONReader::ReadAndReturnValueWithError("[42]", JSON_PARSE_RFC);
- EXPECT_TRUE(root.error_message.empty());
- EXPECT_EQ(0, root.error_code);
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("[42]");
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(parser.GetErrorMessage().empty());
+ EXPECT_EQ(0, parser.error_code());
+ }
// Test each of the error conditions
- root = JSONReader::ReadAndReturnValueWithError("{},{}", JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(JSONParser::FormatErrorMessage(
- 1, 3, JSONReader::kUnexpectedDataAfterRoot),
- root.error_message);
- EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, root.error_code);
-
- std::string nested_json;
- for (int i = 0; i < 201; ++i) {
- nested_json.insert(nested_json.begin(), '[');
- nested_json.append(1, ']');
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("{},{}");
+ EXPECT_FALSE(value);
+ EXPECT_EQ(JSONParser::FormatErrorMessage(
+ 1, 3, JSONParser::kUnexpectedDataAfterRoot),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_UNEXPECTED_DATA_AFTER_ROOT, parser.error_code());
+ }
+
+ {
+ std::string nested_json;
+ for (int i = 0; i < 201; ++i) {
+ nested_json.insert(nested_json.begin(), '[');
+ nested_json.append(1, ']');
+ }
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse(nested_json);
+ EXPECT_FALSE(value);
+ EXPECT_EQ(
+ JSONParser::FormatErrorMessage(1, 200, JSONParser::kTooMuchNesting),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_TOO_MUCH_NESTING, parser.error_code());
+ }
+
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("[1,]");
+ EXPECT_FALSE(value);
+ EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONParser::kTrailingComma),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_TRAILING_COMMA, parser.error_code());
+ }
+
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("{foo:\"bar\"}");
+ EXPECT_FALSE(value);
+ EXPECT_EQ(JSONParser::FormatErrorMessage(
+ 1, 2, JSONParser::kUnquotedDictionaryKey),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_UNQUOTED_DICTIONARY_KEY, parser.error_code());
+ }
+
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("{\"foo\":\"bar\",}");
+ EXPECT_FALSE(value);
+ EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONParser::kTrailingComma),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_TRAILING_COMMA, parser.error_code());
+ }
+
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("[nu]");
+ EXPECT_FALSE(value);
+ EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONParser::kSyntaxError),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_SYNTAX_ERROR, parser.error_code());
+ }
+
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("[\"xxx\\xq\"]");
+ EXPECT_FALSE(value);
+ EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
+ }
+
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("[\"xxx\\uq\"]");
+ EXPECT_FALSE(value);
+ EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
+ }
+
+ {
+ JSONParser parser(JSON_PARSE_RFC);
+ Optional<Value> value = parser.Parse("[\"xxx\\q\"]");
+ EXPECT_FALSE(value);
+ EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
+ parser.GetErrorMessage());
+ EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
}
- root = JSONReader::ReadAndReturnValueWithError(nested_json, JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(JSONParser::FormatErrorMessage(1, 200, JSONReader::kTooMuchNesting),
- root.error_message);
- EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, root.error_code);
-
- root = JSONReader::ReadAndReturnValueWithError("[1,]", JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma),
- root.error_message);
- EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, root.error_code);
-
- root =
- JSONReader::ReadAndReturnValueWithError("{foo:\"bar\"}", JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(
- JSONParser::FormatErrorMessage(1, 2, JSONReader::kUnquotedDictionaryKey),
- root.error_message);
- EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, root.error_code);
-
- root = JSONReader::ReadAndReturnValueWithError("{\"foo\":\"bar\",}",
- JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma),
- root.error_message);
-
- root = JSONReader::ReadAndReturnValueWithError("[nu]", JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError),
- root.error_message);
- EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, root.error_code);
-
- root =
- JSONReader::ReadAndReturnValueWithError("[\"xxx\\xq\"]", JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
- root.error_message);
- EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, root.error_code);
-
- root =
- JSONReader::ReadAndReturnValueWithError("[\"xxx\\uq\"]", JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
- root.error_message);
- EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, root.error_code);
-
- root =
- JSONReader::ReadAndReturnValueWithError("[\"xxx\\q\"]", JSON_PARSE_RFC);
- EXPECT_FALSE(root.value);
- EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
- root.error_message);
- EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, root.error_code);
}
} // namespace internal
diff --git a/chromium/base/json/json_perftest_decodebench.cc b/chromium/base/json/json_perftest_decodebench.cc
index e0f265dde5f..47a659623cb 100644
--- a/chromium/base/json/json_perftest_decodebench.cc
+++ b/chromium/base/json/json_perftest_decodebench.cc
@@ -24,6 +24,7 @@
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
+#include "base/logging.h"
#include "base/time/time.h"
int main(int argc, char* argv[]) {
diff --git a/chromium/base/json/json_reader.cc b/chromium/base/json/json_reader.cc
index 53e3df9fdf3..9456cfde1aa 100644
--- a/chromium/base/json/json_reader.cc
+++ b/chromium/base/json/json_reader.cc
@@ -8,30 +8,10 @@
#include <vector>
#include "base/json/json_parser.h"
-#include "base/notreached.h"
#include "base/optional.h"
namespace base {
-// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
-static_assert(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
- "JSONReader error out of bounds");
-
-const char JSONReader::kInvalidEscape[] = "Invalid escape sequence.";
-const char JSONReader::kSyntaxError[] = "Syntax error.";
-const char JSONReader::kUnexpectedToken[] = "Unexpected token.";
-const char JSONReader::kTrailingComma[] = "Trailing comma not allowed.";
-const char JSONReader::kTooMuchNesting[] = "Too much nesting.";
-const char JSONReader::kUnexpectedDataAfterRoot[] =
- "Unexpected data after root element.";
-const char JSONReader::kUnsupportedEncoding[] =
- "Unsupported encoding. JSON must be UTF-8.";
-const char JSONReader::kUnquotedDictionaryKey[] =
- "Dictionary keys must be quoted.";
-const char JSONReader::kInputTooLarge[] = "Input string is too large (>2GB).";
-const char JSONReader::kUnrepresentableNumber[] =
- "Number cannot be represented.";
-
JSONReader::ValueWithError::ValueWithError() = default;
JSONReader::ValueWithError::ValueWithError(ValueWithError&& other) = default;
@@ -41,11 +21,6 @@ JSONReader::ValueWithError::~ValueWithError() = default;
JSONReader::ValueWithError& JSONReader::ValueWithError::operator=(
ValueWithError&& other) = default;
-JSONReader::JSONReader(int options, size_t max_depth)
- : parser_(new internal::JSONParser(options, max_depth)) {}
-
-JSONReader::~JSONReader() = default;
-
// static
Optional<Value> JSONReader::Read(StringPiece json,
int options,
@@ -54,6 +29,7 @@ Optional<Value> JSONReader::Read(StringPiece json,
return parser.Parse(json);
}
+// static
std::unique_ptr<Value> JSONReader::ReadDeprecated(StringPiece json,
int options,
size_t max_depth) {
@@ -77,72 +53,4 @@ JSONReader::ValueWithError JSONReader::ReadAndReturnValueWithError(
return ret;
}
-// static
-std::unique_ptr<Value> JSONReader::ReadAndReturnErrorDeprecated(
- StringPiece json,
- int options,
- int* error_code_out,
- std::string* error_msg_out,
- int* error_line_out,
- int* error_column_out) {
- ValueWithError ret = ReadAndReturnValueWithError(json, options);
- if (ret.value)
- return Value::ToUniquePtrValue(std::move(*ret.value));
-
- if (error_code_out)
- *error_code_out = ret.error_code;
- if (error_msg_out)
- *error_msg_out = ret.error_message;
- if (error_line_out)
- *error_line_out = ret.error_line;
- if (error_column_out)
- *error_column_out = ret.error_column;
- return nullptr;
-}
-
-// static
-std::string JSONReader::ErrorCodeToString(JsonParseError error_code) {
- switch (error_code) {
- case JSON_NO_ERROR:
- return std::string();
- case JSON_INVALID_ESCAPE:
- return kInvalidEscape;
- case JSON_SYNTAX_ERROR:
- return kSyntaxError;
- case JSON_UNEXPECTED_TOKEN:
- return kUnexpectedToken;
- case JSON_TRAILING_COMMA:
- return kTrailingComma;
- case JSON_TOO_MUCH_NESTING:
- return kTooMuchNesting;
- case JSON_UNEXPECTED_DATA_AFTER_ROOT:
- return kUnexpectedDataAfterRoot;
- case JSON_UNSUPPORTED_ENCODING:
- return kUnsupportedEncoding;
- case JSON_UNQUOTED_DICTIONARY_KEY:
- return kUnquotedDictionaryKey;
- case JSON_TOO_LARGE:
- return kInputTooLarge;
- case JSON_UNREPRESENTABLE_NUMBER:
- return kUnrepresentableNumber;
- case JSON_PARSE_ERROR_COUNT:
- break;
- }
- NOTREACHED();
- return std::string();
-}
-
-Optional<Value> JSONReader::ReadToValue(StringPiece json) {
- return parser_->Parse(json);
-}
-
-std::unique_ptr<Value> JSONReader::ReadToValueDeprecated(StringPiece json) {
- Optional<Value> value = parser_->Parse(json);
- return value ? std::make_unique<Value>(std::move(*value)) : nullptr;
-}
-
-std::string JSONReader::GetErrorMessage() const {
- return parser_->GetErrorMessage();
-}
-
} // namespace base
diff --git a/chromium/base/json/json_reader.h b/chromium/base/json/json_reader.h
index 511fffe32e7..007f843d736 100644
--- a/chromium/base/json/json_reader.h
+++ b/chromium/base/json/json_reader.h
@@ -49,10 +49,6 @@
namespace base {
-namespace internal {
-class JSONParser;
-}
-
enum JSONParserOptions {
// Parses the input strictly according to RFC 8259, except for where noted
// above.
@@ -70,22 +66,6 @@ enum JSONParserOptions {
class BASE_EXPORT JSONReader {
public:
- // Error codes during parsing.
- enum JsonParseError {
- JSON_NO_ERROR = 0,
- JSON_INVALID_ESCAPE,
- JSON_SYNTAX_ERROR,
- JSON_UNEXPECTED_TOKEN,
- JSON_TRAILING_COMMA,
- JSON_TOO_MUCH_NESTING,
- JSON_UNEXPECTED_DATA_AFTER_ROOT,
- JSON_UNSUPPORTED_ENCODING,
- JSON_UNQUOTED_DICTIONARY_KEY,
- JSON_TOO_LARGE,
- JSON_UNREPRESENTABLE_NUMBER,
- JSON_PARSE_ERROR_COUNT
- };
-
struct BASE_EXPORT ValueWithError {
ValueWithError();
ValueWithError(ValueWithError&& other);
@@ -96,7 +76,7 @@ class BASE_EXPORT JSONReader {
// Contains default values if |value| exists, or the error status if |value|
// is base::nullopt.
- JsonParseError error_code = JSON_NO_ERROR;
+ int error_code = ValueDeserializer::kErrorCodeNoError;
std::string error_message;
int error_line = 0;
int error_column = 0;
@@ -104,24 +84,6 @@ class BASE_EXPORT JSONReader {
DISALLOW_COPY_AND_ASSIGN(ValueWithError);
};
- // String versions of parse error codes.
- static const char kInvalidEscape[];
- static const char kSyntaxError[];
- static const char kUnexpectedToken[];
- static const char kTrailingComma[];
- static const char kTooMuchNesting[];
- static const char kUnexpectedDataAfterRoot[];
- static const char kUnsupportedEncoding[];
- static const char kUnquotedDictionaryKey[];
- static const char kInputTooLarge[];
- static const char kUnrepresentableNumber[];
-
- // Constructs a reader.
- JSONReader(int options = JSON_PARSE_RFC,
- size_t max_depth = internal::kAbsoluteMaxDepth);
-
- ~JSONReader();
-
// Reads and parses |json|, returning a Value.
// If |json| is not a properly formed JSON string, returns base::nullopt.
static Optional<Value> Read(StringPiece json,
@@ -145,36 +107,9 @@ class BASE_EXPORT JSONReader {
StringPiece json,
int options = JSON_PARSE_RFC);
- // Deprecated. Use the ReadAndReturnValueWithError() method above.
- // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
- // are optional. If specified and nullptr is returned, they will be populated
- // an error code and a formatted error message (including error location if
- // appropriate). Otherwise, they will be unmodified.
- static std::unique_ptr<Value> ReadAndReturnErrorDeprecated(
- StringPiece json,
- int options, // JSONParserOptions
- int* error_code_out,
- std::string* error_msg_out,
- int* error_line_out = nullptr,
- int* error_column_out = nullptr);
-
- // Converts a JSON parse error code into a human readable message.
- // Returns an empty string if error_code is JSON_NO_ERROR.
- static std::string ErrorCodeToString(JsonParseError error_code);
-
- // Non-static version of Read() above.
- Optional<Value> ReadToValue(StringPiece json);
-
- // Deprecated. Use the ReadToValue() method above.
- // Non-static version of Read() above.
- std::unique_ptr<Value> ReadToValueDeprecated(StringPiece json);
-
- // Converts error_code_ to a human-readable string, including line and column
- // numbers if appropriate.
- std::string GetErrorMessage() const;
-
- private:
- std::unique_ptr<internal::JSONParser> parser_;
+ // This class contains only static methods.
+ JSONReader() = delete;
+ DISALLOW_COPY_AND_ASSIGN(JSONReader);
};
} // namespace base
diff --git a/chromium/base/json/json_reader_fuzzer.cc b/chromium/base/json/json_reader_fuzzer.cc
index 68b4dc0231a..5f27ac23b17 100644
--- a/chromium/base/json/json_reader_fuzzer.cc
+++ b/chromium/base/json/json_reader_fuzzer.cc
@@ -24,7 +24,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
JSONReader::ValueWithError json_val =
JSONReader::ReadAndReturnValueWithError(input_string, options);
- CHECK((json_val.error_code == JSONReader::JSON_NO_ERROR) ==
+ CHECK((json_val.error_code == base::ValueDeserializer::kErrorCodeNoError) ==
json_val.value.has_value());
if (json_val.value) {
diff --git a/chromium/base/json/json_reader_unittest.cc b/chromium/base/json/json_reader_unittest.cc
index 33570ad4b48..519a8845ea5 100644
--- a/chromium/base/json/json_reader_unittest.cc
+++ b/chromium/base/json/json_reader_unittest.cc
@@ -189,7 +189,8 @@ TEST(JSONReaderTest, Doubles) {
auto value_with_error =
JSONReader::ReadAndReturnValueWithError("1e1000", JSON_PARSE_RFC);
ASSERT_FALSE(value_with_error.value);
- ASSERT_NE(value_with_error.error_code, JSONReader::JSON_NO_ERROR);
+ ASSERT_NE(base::ValueDeserializer::kErrorCodeNoError,
+ value_with_error.error_code);
}
TEST(JSONReaderTest, FractionalNumbers) {
@@ -647,10 +648,10 @@ TEST(JSONReaderTest, ReadFromFile) {
std::string input;
ASSERT_TRUE(ReadFileToString(path.AppendASCII("bom_feff.json"), &input));
- JSONReader reader;
- Optional<Value> root(reader.ReadToValue(input));
- ASSERT_TRUE(root) << reader.GetErrorMessage();
- EXPECT_TRUE(root->is_dict());
+ JSONReader::ValueWithError root =
+ JSONReader::ReadAndReturnValueWithError(input);
+ ASSERT_TRUE(root.value) << root.error_message;
+ EXPECT_TRUE(root.value->is_dict());
}
// Tests that the root of a JSON object can be deleted safely while its
@@ -736,19 +737,21 @@ TEST(JSONReaderTest, InvalidSanity) {
};
for (size_t i = 0; i < base::size(kInvalidJson); ++i) {
- JSONReader reader;
LOG(INFO) << "Sanity test " << i << ": <" << kInvalidJson[i] << ">";
- EXPECT_FALSE(reader.ReadToValue(kInvalidJson[i]));
- EXPECT_NE("", reader.GetErrorMessage());
+ JSONReader::ValueWithError root =
+ JSONReader::ReadAndReturnValueWithError(kInvalidJson[i]);
+ EXPECT_FALSE(root.value);
+ EXPECT_NE("", root.error_message);
}
}
TEST(JSONReaderTest, IllegalTrailingNull) {
const char json[] = {'"', 'n', 'u', 'l', 'l', '"', '\0'};
std::string json_string(json, sizeof(json));
- JSONReader reader;
- EXPECT_FALSE(reader.ReadToValue(json_string));
- EXPECT_NE("", reader.GetErrorMessage());
+ JSONReader::ValueWithError root =
+ JSONReader::ReadAndReturnValueWithError(json_string);
+ EXPECT_FALSE(root.value);
+ EXPECT_NE("", root.error_message);
}
TEST(JSONReaderTest, ASCIIControlCodes) {
@@ -833,10 +836,18 @@ TEST(JSONReaderTest, DecodeNegativeEscapeSequence) {
// Verifies invalid code points are replaced.
TEST(JSONReaderTest, ReplaceInvalidCharacters) {
- // U+D800 is a lone surrogate.
- const std::string invalid = "\"\xED\xA0\x80\"";
+ // U+D800 is a lone high surrogate.
+ const std::string invalid_high = "\"\xED\xA0\x80\"";
Optional<Value> value =
- JSONReader::Read(invalid, JSON_REPLACE_INVALID_CHARACTERS);
+ JSONReader::Read(invalid_high, JSON_REPLACE_INVALID_CHARACTERS);
+ ASSERT_TRUE(value);
+ ASSERT_TRUE(value->is_string());
+ // Expect three U+FFFD (one for each UTF-8 byte in the invalid code point).
+ EXPECT_EQ("\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD", value->GetString());
+
+ // U+DFFF is a lone low surrogate.
+ const std::string invalid_low = "\"\xED\xBF\xBF\"";
+ value = JSONReader::Read(invalid_low, JSON_REPLACE_INVALID_CHARACTERS);
ASSERT_TRUE(value);
ASSERT_TRUE(value->is_string());
// Expect three U+FFFD (one for each UTF-8 byte in the invalid code point).
@@ -844,10 +855,17 @@ TEST(JSONReaderTest, ReplaceInvalidCharacters) {
}
TEST(JSONReaderTest, ReplaceInvalidUTF16EscapeSequence) {
- // U+D800 is a lone surrogate.
- const std::string invalid = "\"_\\uD800_\"";
+ // U+D800 is a lone high surrogate.
+ const std::string invalid_high = "\"_\\uD800_\"";
Optional<Value> value =
- JSONReader::Read(invalid, JSON_REPLACE_INVALID_CHARACTERS);
+ JSONReader::Read(invalid_high, JSON_REPLACE_INVALID_CHARACTERS);
+ ASSERT_TRUE(value);
+ ASSERT_TRUE(value->is_string());
+ EXPECT_EQ("_\xEF\xBF\xBD_", value->GetString());
+
+ // U+DFFF is a lone low surrogate.
+ const std::string invalid_low = "\"_\\uDFFF_\"";
+ value = JSONReader::Read(invalid_low, JSON_REPLACE_INVALID_CHARACTERS);
ASSERT_TRUE(value);
ASSERT_TRUE(value->is_string());
EXPECT_EQ("_\xEF\xBF\xBD_", value->GetString());
diff --git a/chromium/base/json/json_string_value_serializer.cc b/chromium/base/json/json_string_value_serializer.cc
index 0ec48ca57fe..d98a62e37f9 100644
--- a/chromium/base/json/json_string_value_serializer.cc
+++ b/chromium/base/json/json_string_value_serializer.cc
@@ -49,6 +49,14 @@ JSONStringValueDeserializer::~JSONStringValueDeserializer() = default;
std::unique_ptr<Value> JSONStringValueDeserializer::Deserialize(
int* error_code,
std::string* error_str) {
- return base::JSONReader::ReadAndReturnErrorDeprecated(json_string_, options_,
- error_code, error_str);
+ base::JSONReader::ValueWithError ret =
+ base::JSONReader::ReadAndReturnValueWithError(json_string_, options_);
+ if (ret.value)
+ return base::Value::ToUniquePtrValue(std::move(*ret.value));
+
+ if (error_code)
+ *error_code = ret.error_code;
+ if (error_str)
+ *error_str = std::move(ret.error_message);
+ return nullptr;
}
diff --git a/chromium/base/json/json_value_serializer_unittest.cc b/chromium/base/json/json_value_serializer_unittest.cc
index 5722cb0f0dd..3b102a12274 100644
--- a/chromium/base/json/json_value_serializer_unittest.cc
+++ b/chromium/base/json/json_value_serializer_unittest.cc
@@ -133,12 +133,15 @@ TEST(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) {
ASSERT_FALSE(value);
ASSERT_NE(0, error_code);
ASSERT_FALSE(error_message.empty());
- // Repeat with commas allowed.
+ // Repeat with commas allowed. The Deserialize call shouldn't change the
+ // value of error_code. To test that, we first set it to a nonsense value
+ // (-789) and ASSERT_EQ that it remains that nonsense value.
+ error_code = -789;
JSONStringValueDeserializer str_deserializer2(kProperJSONWithCommas,
JSON_ALLOW_TRAILING_COMMAS);
value = str_deserializer2.Deserialize(&error_code, &error_message);
ASSERT_TRUE(value);
- ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+ ASSERT_EQ(-789, error_code);
// Verify if the same JSON is still there.
CheckJSONIsStillTheSame(*value);
}
@@ -184,12 +187,15 @@ TEST(JSONValueDeserializerTest, ReadJSONWithCommasFromFile) {
ASSERT_FALSE(value);
ASSERT_NE(0, error_code);
ASSERT_FALSE(error_message.empty());
- // Repeat with commas allowed.
+ // Repeat with commas allowed. The Deserialize call shouldn't change the
+ // value of error_code. To test that, we first set it to a nonsense value
+ // (-789) and ASSERT_EQ that it remains that nonsense value.
+ error_code = -789;
JSONFileValueDeserializer file_deserializer2(temp_file,
JSON_ALLOW_TRAILING_COMMAS);
value = file_deserializer2.Deserialize(&error_code, &error_message);
ASSERT_TRUE(value);
- ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+ ASSERT_EQ(-789, error_code);
// Verify if the same JSON is still there.
CheckJSONIsStillTheSame(*value);
}