summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorerikkay@chromium.org <erikkay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-06 15:42:39 +0000
committererikkay@chromium.org <erikkay@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-06 15:42:39 +0000
commitba3996771f6d19298ee655992b2f6291a314ea76 (patch)
treee5d88f89e7e98aa6ee60af431dc5dfa426d727b2 /base
parent44a91f51ec8dd8d1373e28ef6f3f0ab410db942f (diff)
downloadchromium_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.cc89
-rw-r--r--base/json/json_reader.h52
-rw-r--r--base/json/json_reader_unittest.cc43
-rw-r--r--base/values.h8
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_