diff options
author | erikkay@chromium.org <erikkay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-06 15:42:39 +0000 |
---|---|---|
committer | erikkay@chromium.org <erikkay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-06 15:42:39 +0000 |
commit | ba3996771f6d19298ee655992b2f6291a314ea76 (patch) | |
tree | e5d88f89e7e98aa6ee60af431dc5dfa426d727b2 /base | |
parent | 44a91f51ec8dd8d1373e28ef6f3f0ab410db942f (diff) | |
download | chromium_src-ba3996771f6d19298ee655992b2f6291a314ea76.zip chromium_src-ba3996771f6d19298ee655992b2f6291a314ea76.tar.gz chromium_src-ba3996771f6d19298ee655992b2f6291a314ea76.tar.bz2 |
detect preferences errors
BUG=38352
TEST=none
Review URL: http://codereview.chromium.org/1120006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@43715 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/json/json_reader.cc | 89 | ||||
-rw-r--r-- | base/json/json_reader.h | 52 | ||||
-rw-r--r-- | base/json/json_reader_unittest.cc | 43 | ||||
-rw-r--r-- | base/values.h | 8 |
4 files changed, 138 insertions, 54 deletions
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc index bdc682b..cf9ce02 100644 --- a/base/json/json_reader.cc +++ b/base/json/json_reader.cc @@ -95,40 +95,79 @@ const char* JSONReader::kUnquotedDictionaryKey = /* static */ Value* JSONReader::Read(const std::string& json, bool allow_trailing_comma) { - return ReadAndReturnError(json, allow_trailing_comma, NULL); + return ReadAndReturnError(json, allow_trailing_comma, NULL, NULL); } /* static */ Value* JSONReader::ReadAndReturnError(const std::string& json, bool allow_trailing_comma, - std::string *error_message_out) { + int* error_code_out, + std::string* error_msg_out) { JSONReader reader = JSONReader(); Value* root = reader.JsonToValue(json, true, allow_trailing_comma); if (root) return root; - if (error_message_out) - *error_message_out = reader.error_message(); + if (error_code_out) + *error_code_out = reader.error_code(); + if (error_msg_out) + *error_msg_out = reader.GetErrorMessage(); return NULL; } /* static */ std::string JSONReader::FormatErrorMessage(int line, int column, - const char* description) { - return StringPrintf("Line: %i, column: %i, %s", - line, column, description); + const std::string& description) { + if (line || column) { + return StringPrintf("Line: %i, column: %i, %s", + line, column, description.c_str()); + } + return description; +} + +/* static */ +std::string JSONReader::ErrorCodeToString(JsonParseError error_code) { + switch (error_code) { + case JSON_NO_ERROR: + return std::string(); + case JSON_BAD_ROOT_ELEMENT_TYPE: + return kBadRootElementType; + case JSON_INVALID_ESCAPE: + return kInvalidEscape; + case JSON_SYNTAX_ERROR: + return kSyntaxError; + 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; + default: + NOTREACHED(); + return std::string(); + } +} + +std::string JSONReader::GetErrorMessage() const { + return FormatErrorMessage(error_line_, error_col_, + ErrorCodeToString(error_code_)); } JSONReader::JSONReader() : start_pos_(NULL), json_pos_(NULL), stack_depth_(0), - allow_trailing_comma_(false) {} + allow_trailing_comma_(false), + error_code_(JSON_NO_ERROR), error_line_(0), error_col_(0) {} Value* JSONReader::JsonToValue(const std::string& json, bool check_root, bool allow_trailing_comma) { // The input must be in UTF-8. if (!IsStringUTF8(json.c_str())) { - error_message_ = kUnsupportedEncoding; + error_code_ = JSON_UNSUPPORTED_ENCODING; return NULL; } @@ -149,20 +188,20 @@ Value* JSONReader::JsonToValue(const std::string& json, bool check_root, json_pos_ = start_pos_; allow_trailing_comma_ = allow_trailing_comma; stack_depth_ = 0; - error_message_.clear(); + error_code_ = JSON_NO_ERROR; scoped_ptr<Value> root(BuildValue(check_root)); if (root.get()) { if (ParseToken().type == Token::END_OF_INPUT) { return root.release(); } else { - SetErrorMessage(kUnexpectedDataAfterRoot, json_pos_); + SetErrorCode(JSON_UNEXPECTED_DATA_AFTER_ROOT, json_pos_); } } // Default to calling errors "syntax errors". - if (error_message_.empty()) - SetErrorMessage(kSyntaxError, json_pos_); + if (error_code_ == 0) + SetErrorCode(JSON_SYNTAX_ERROR, json_pos_); return NULL; } @@ -170,7 +209,7 @@ Value* JSONReader::JsonToValue(const std::string& json, bool check_root, Value* JSONReader::BuildValue(bool is_root) { ++stack_depth_; if (stack_depth_ > kStackLimit) { - SetErrorMessage(kTooMuchNesting, json_pos_); + SetErrorCode(JSON_TOO_MUCH_NESTING, json_pos_); return NULL; } @@ -178,7 +217,7 @@ Value* JSONReader::BuildValue(bool is_root) { // The root token must be an array or an object. if (is_root && token.type != Token::OBJECT_BEGIN && token.type != Token::ARRAY_BEGIN) { - SetErrorMessage(kBadRootElementType, json_pos_); + SetErrorCode(JSON_BAD_ROOT_ELEMENT_TYPE, json_pos_); return NULL; } @@ -234,7 +273,7 @@ Value* JSONReader::BuildValue(bool is_root) { // consumers need the parsing leniency, so handle accordingly. if (token.type == Token::ARRAY_END) { if (!allow_trailing_comma_) { - SetErrorMessage(kTrailingComma, json_pos_); + SetErrorCode(JSON_TRAILING_COMMA, json_pos_); return NULL; } // Trailing comma OK, stop parsing the Array. @@ -259,7 +298,7 @@ Value* JSONReader::BuildValue(bool is_root) { node.reset(new DictionaryValue); while (token.type != Token::OBJECT_END) { if (token.type != Token::STRING) { - SetErrorMessage(kUnquotedDictionaryKey, json_pos_); + SetErrorCode(JSON_UNQUOTED_DICTIONARY_KEY, json_pos_); return NULL; } scoped_ptr<Value> dict_key_value(DecodeString(token)); @@ -294,7 +333,7 @@ Value* JSONReader::BuildValue(bool is_root) { // consumers need the parsing leniency, so handle accordingly. if (token.type == Token::OBJECT_END) { if (!allow_trailing_comma_) { - SetErrorMessage(kTrailingComma, json_pos_); + SetErrorCode(JSON_TRAILING_COMMA, json_pos_); return NULL; } // Trailing comma OK, stop parsing the Object. @@ -384,13 +423,13 @@ JSONReader::Token JSONReader::ParseStringToken() { switch (c) { case 'x': if (!ReadHexDigits(token, 2)) { - SetErrorMessage(kInvalidEscape, json_pos_ + token.length); + SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); return kInvalidToken; } break; case 'u': if (!ReadHexDigits(token, 4)) { - SetErrorMessage(kInvalidEscape, json_pos_ + token.length); + SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); return kInvalidToken; } break; @@ -405,7 +444,7 @@ JSONReader::Token JSONReader::ParseStringToken() { case '"': break; default: - SetErrorMessage(kInvalidEscape, json_pos_ + token.length); + SetErrorCode(JSON_INVALID_ESCAPE, json_pos_ + token.length); return kInvalidToken; } } else if ('"' == c) { @@ -617,8 +656,8 @@ bool JSONReader::EatComment() { return true; } -void JSONReader::SetErrorMessage(const char* description, - const wchar_t* error_pos) { +void JSONReader::SetErrorCode(JsonParseError error, + const wchar_t* error_pos) { int line_number = 1; int column_number = 1; @@ -637,7 +676,9 @@ void JSONReader::SetErrorMessage(const char* description, } } - error_message_ = FormatErrorMessage(line_number, column_number, description); + error_line_ = line_number; + error_col_ = column_number; + error_code_ = error; } } // namespace base diff --git a/base/json/json_reader.h b/base/json/json_reader.h index 47598f4..aa0c2a7 100644 --- a/base/json/json_reader.h +++ b/base/json/json_reader.h @@ -82,7 +82,20 @@ class JSONReader { } }; - // Error messages that can be returned. + // Error codes during parsing. + enum JsonParseError { + JSON_NO_ERROR = 0, + JSON_BAD_ROOT_ELEMENT_TYPE, + JSON_INVALID_ESCAPE, + JSON_SYNTAX_ERROR, + JSON_TRAILING_COMMA, + JSON_TOO_MUCH_NESTING, + JSON_UNEXPECTED_DATA_AFTER_ROOT, + JSON_UNSUPPORTED_ENCODING, + JSON_UNQUOTED_DICTIONARY_KEY, + }; + + // String versions of parse error codes. static const char* kBadRootElementType; static const char* kInvalidEscape; static const char* kSyntaxError; @@ -100,17 +113,26 @@ class JSONReader { // objects and arrays even though this goes against the RFC. static Value* Read(const std::string& json, bool allow_trailing_comma); - // Reads and parses |json| like Read(). |error_message_out| is optional. If - // specified and NULL is returned, |error_message_out| will be populated with - // a string describing the error. Otherwise, |error_message_out| is - // unmodified. + // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out| + // are optional. If specified and NULL 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 Value* ReadAndReturnError(const std::string& json, bool allow_trailing_comma, - std::string* error_message_out); + int* error_code_out, + std::string* error_msg_out); + + // 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); + + // Returns the error code if the last call to JsonToValue() failed. + // Returns JSON_NO_ERROR otherwise. + JsonParseError error_code() const { return error_code_; } - // Returns the error message if the last call to JsonToValue() failed. If the - // last call did not fail, returns a valid empty string. - std::string error_message() { return error_message_; } + // Converts error_code_ to a human-readable string, including line and column + // numbers if appropriate. + std::string GetErrorMessage() const; // Reads and parses |json|, returning a Value. The caller owns the returned // instance. If |json| is not a properly formed JSON string, returns NULL and @@ -124,7 +146,7 @@ class JSONReader { private: static std::string FormatErrorMessage(int line, int column, - const char* description); + const std::string& description); DISALLOW_COPY_AND_ASSIGN(JSONReader); @@ -170,9 +192,9 @@ class JSONReader { // Checks if |json_pos_| matches str. bool NextStringMatch(const std::wstring& str); - // Creates the error message that will be returned to the caller. The current + // Sets the error code that will be returned to the caller. The current // line and column are determined and added into the final message. - void SetErrorMessage(const char* description, const wchar_t* error_pos); + void SetErrorCode(const JsonParseError error, const wchar_t* error_pos); // Pointer to the starting position in the input string. const wchar_t* start_pos_; @@ -186,8 +208,10 @@ class JSONReader { // A parser flag that allows trailing commas in objects and arrays. bool allow_trailing_comma_; - // Contains the error message for the last call to JsonToValue(), if any. - std::string error_message_; + // Contains the error code for the last call to JsonToValue(), if any. + JsonParseError error_code_; + int error_line_; + int error_col_; }; } // namespace base diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc index 17dea56..71649df 100644 --- a/base/json/json_reader_unittest.cc +++ b/base/json/json_reader_unittest.cc @@ -468,23 +468,30 @@ TEST(JSONReaderTest, Reading) { TEST(JSONReaderTest, ErrorMessages) { // Error strings should not be modified in case of success. std::string error_message; + int error_code = 0; scoped_ptr<Value> root; - root.reset(JSONReader::ReadAndReturnError("[42]", false, &error_message)); + root.reset(JSONReader::ReadAndReturnError("[42]", false, + &error_code, &error_message)); EXPECT_TRUE(error_message.empty()); + EXPECT_EQ(0, error_code); // Test line and column counting const char* big_json = "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]"; // error here --------------------------------^ - root.reset(JSONReader::ReadAndReturnError(big_json, false, &error_message)); + root.reset(JSONReader::ReadAndReturnError(big_json, false, + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(5, 9, JSONReader::kSyntaxError), error_message); + EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); // Test each of the error conditions - root.reset(JSONReader::ReadAndReturnError("{},{}", false, &error_message)); + root.reset(JSONReader::ReadAndReturnError("{},{}", false, + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 3, JSONReader::kUnexpectedDataAfterRoot), error_message); + EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, error_code); std::string nested_json; for (int i = 0; i < 101; ++i) { @@ -492,56 +499,66 @@ TEST(JSONReaderTest, ErrorMessages) { nested_json.append(1, ']'); } root.reset(JSONReader::ReadAndReturnError(nested_json, false, - &error_message)); + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 101, JSONReader::kTooMuchNesting), error_message); + EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code); - root.reset(JSONReader::ReadAndReturnError("42", false, &error_message)); + root.reset(JSONReader::ReadAndReturnError("42", false, + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 1, JSONReader::kBadRootElementType), error_message); + EXPECT_EQ(JSONReader::JSON_BAD_ROOT_ELEMENT_TYPE, error_code); - root.reset(JSONReader::ReadAndReturnError("[1,]", false, &error_message)); + root.reset(JSONReader::ReadAndReturnError("[1,]", false, + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 4, JSONReader::kTrailingComma), error_message); + EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code); root.reset(JSONReader::ReadAndReturnError("{foo:\"bar\"}", false, - &error_message)); + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 2, JSONReader::kUnquotedDictionaryKey), error_message); + EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code); root.reset(JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}", false, - &error_message)); + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 14, JSONReader::kTrailingComma), error_message); - root.reset(JSONReader::ReadAndReturnError("[nu]", false, &error_message)); + root.reset(JSONReader::ReadAndReturnError("[nu]", false, + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 2, JSONReader::kSyntaxError), error_message); + EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code); root.reset(JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", false, - &error_message)); + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), error_message); + EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); root.reset(JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", false, - &error_message)); + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), error_message); + EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); root.reset(JSONReader::ReadAndReturnError("[\"xxx\\q\"]", false, - &error_message)); + &error_code, &error_message)); EXPECT_FALSE(root.get()); EXPECT_EQ(JSONReader::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape), error_message); - + EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code); } } // namespace base diff --git a/base/values.h b/base/values.h index ac6307a..44af9c1 100644 --- a/base/values.h +++ b/base/values.h @@ -431,9 +431,11 @@ class ValueSerializer { // This method deserializes the subclass-specific format into a Value object. // If the return value is non-NULL, the caller takes ownership of returned - // Value. If the return value is NULL, and if error_message is non-NULL, - // error_message should be filled with a message describing the error. - virtual Value* Deserialize(std::string* error_message) = 0; + // Value. If the return value is NULL, and if error_code is non-NULL, + // error_code will be set with the underlying error. + // If |error_message| is non-null, it will be filled in with a formatted + // error message including the location of the error if appropriate. + virtual Value* Deserialize(int* error_code, std::string* error_str) = 0; }; #endif // BASE_VALUES_H_ |