Allow JSONWriter and JSONValueSerializer to ignore binary values when instructed to do so.

Design discussion is available here: http://groups.google.com/a/chromium.org/group/chromium-dev/browse_thread/thread/967eb64325c24f9c

BUG=None
TEST=base_unittests


Review URL: http://codereview.chromium.org/8505033

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110021 0039d316-1c4b-4281-b951-d872f2087c98
parent 16d57d91
...@@ -17,10 +17,24 @@ const char* JSONFileValueSerializer::kNoSuchFile = "File doesn't exist."; ...@@ -17,10 +17,24 @@ const char* JSONFileValueSerializer::kNoSuchFile = "File doesn't exist.";
JSONStringValueSerializer::~JSONStringValueSerializer() {} JSONStringValueSerializer::~JSONStringValueSerializer() {}
bool JSONStringValueSerializer::Serialize(const Value& root) { bool JSONStringValueSerializer::Serialize(const Value& root) {
return SerializeInternal(root, false);
}
bool JSONStringValueSerializer::SerializeAndOmitBinaryValues(
const Value& root) {
return SerializeInternal(root, true);
}
bool JSONStringValueSerializer::SerializeInternal(const Value& root,
bool omit_binary_values) {
if (!json_string_ || initialized_with_const_string_) if (!json_string_ || initialized_with_const_string_)
return false; return false;
base::JSONWriter::Write(&root, pretty_print_, json_string_); base::JSONWriter::WriteWithOptions(
&root,
pretty_print_,
omit_binary_values ? base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES : 0,
json_string_);
return true; return true;
} }
...@@ -38,10 +52,21 @@ Value* JSONStringValueSerializer::Deserialize(int* error_code, ...@@ -38,10 +52,21 @@ Value* JSONStringValueSerializer::Deserialize(int* error_code,
/******* File Serializer *******/ /******* File Serializer *******/
bool JSONFileValueSerializer::Serialize(const Value& root) { bool JSONFileValueSerializer::Serialize(const Value& root) {
return SerializeInternal(root, false);
}
bool JSONFileValueSerializer::SerializeAndOmitBinaryValues(const Value& root) {
return SerializeInternal(root, true);
}
bool JSONFileValueSerializer::SerializeInternal(const Value& root,
bool omit_binary_values) {
std::string json_string; std::string json_string;
JSONStringValueSerializer serializer(&json_string); JSONStringValueSerializer serializer(&json_string);
serializer.set_pretty_print(true); serializer.set_pretty_print(true);
bool result = serializer.Serialize(root); bool result = omit_binary_values ?
serializer.SerializeAndOmitBinaryValues(root) :
serializer.Serialize(root);
if (!result) if (!result)
return false; return false;
......
...@@ -39,7 +39,11 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer { ...@@ -39,7 +39,11 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
// Attempt to serialize the data structure represented by Value into // Attempt to serialize the data structure represented by Value into
// JSON. If the return value is true, the result will have been written // JSON. If the return value is true, the result will have been written
// into the string passed into the constructor. // into the string passed into the constructor.
virtual bool Serialize(const Value& root); virtual bool Serialize(const Value& root) OVERRIDE;
// Equivalent to Serialize(root) except binary values are omitted from the
// output.
bool SerializeAndOmitBinaryValues(const Value& root);
// Attempt to deserialize the data structure encoded in the string passed // Attempt to deserialize the data structure encoded in the string passed
// in to the constructor into a structure of Value objects. If the return // in to the constructor into a structure of Value objects. If the return
...@@ -48,7 +52,8 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer { ...@@ -48,7 +52,8 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
// If |error_message| is non-null, it will be filled in with a formatted // If |error_message| is non-null, it will be filled in with a formatted
// error message including the location of the error if appropriate. // error message including the location of the error if appropriate.
// The caller takes ownership of the returned value. // The caller takes ownership of the returned value.
virtual Value* Deserialize(int* error_code, std::string* error_message); virtual Value* Deserialize(int* error_code, std::string* error_message)
OVERRIDE;
void set_pretty_print(bool new_value) { pretty_print_ = new_value; } void set_pretty_print(bool new_value) { pretty_print_ = new_value; }
bool pretty_print() { return pretty_print_; } bool pretty_print() { return pretty_print_; }
...@@ -58,6 +63,8 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer { ...@@ -58,6 +63,8 @@ class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
} }
private: private:
bool SerializeInternal(const Value& root, bool omit_binary_values);
std::string* json_string_; std::string* json_string_;
bool initialized_with_const_string_; bool initialized_with_const_string_;
bool pretty_print_; // If true, serialization will span multiple lines. bool pretty_print_; // If true, serialization will span multiple lines.
...@@ -86,7 +93,11 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer { ...@@ -86,7 +93,11 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
// Attempt to serialize the data structure represented by Value into // Attempt to serialize the data structure represented by Value into
// JSON. If the return value is true, the result will have been written // JSON. If the return value is true, the result will have been written
// into the file whose name was passed into the constructor. // into the file whose name was passed into the constructor.
virtual bool Serialize(const Value& root); virtual bool Serialize(const Value& root) OVERRIDE;
// Equivalent to Serialize(root) except binary values are omitted from the
// output.
bool SerializeAndOmitBinaryValues(const Value& root);
// Attempt to deserialize the data structure encoded in the file passed // Attempt to deserialize the data structure encoded in the file passed
// in to the constructor into a structure of Value objects. If the return // in to the constructor into a structure of Value objects. If the return
...@@ -95,7 +106,8 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer { ...@@ -95,7 +106,8 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
// If |error_message| is non-null, it will be filled in with a formatted // If |error_message| is non-null, it will be filled in with a formatted
// error message including the location of the error if appropriate. // error message including the location of the error if appropriate.
// The caller takes ownership of the returned value. // The caller takes ownership of the returned value.
virtual Value* Deserialize(int* error_code, std::string* error_message); virtual Value* Deserialize(int* error_code, std::string* error_message)
OVERRIDE;
// This enum is designed to safely overlap with JSONReader::JsonParseError. // This enum is designed to safely overlap with JSONReader::JsonParseError.
enum JsonFileError { enum JsonFileError {
...@@ -117,6 +129,8 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer { ...@@ -117,6 +129,8 @@ class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
static const char* GetErrorMessageForCode(int error_code); static const char* GetErrorMessageForCode(int error_code);
private: private:
bool SerializeInternal(const Value& root, bool omit_binary_values);
FilePath json_file_path_; FilePath json_file_path_;
// A wrapper for file_util::ReadFileToString which returns a non-zero // A wrapper for file_util::ReadFileToString which returns a non-zero
......
// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -26,19 +26,21 @@ const char* JSONWriter::kEmptyArray = "[]"; ...@@ -26,19 +26,21 @@ const char* JSONWriter::kEmptyArray = "[]";
void JSONWriter::Write(const Value* const node, void JSONWriter::Write(const Value* const node,
bool pretty_print, bool pretty_print,
std::string* json) { std::string* json) {
WriteWithOptionalEscape(node, pretty_print, true, json); WriteWithOptions(node, pretty_print, 0, json);
} }
/* static */ /* static */
void JSONWriter::WriteWithOptionalEscape(const Value* const node, void JSONWriter::WriteWithOptions(const Value* const node,
bool pretty_print, bool pretty_print,
bool escape, int options,
std::string* json) { std::string* json) {
json->clear(); json->clear();
// Is there a better way to estimate the size of the output? // Is there a better way to estimate the size of the output?
json->reserve(1024); json->reserve(1024);
JSONWriter writer(pretty_print, json); JSONWriter writer(pretty_print, json);
writer.BuildJSONString(node, 0, escape); bool escape = !(options & OPTIONS_DO_NOT_ESCAPE);
bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES);
writer.BuildJSONString(node, 0, escape, omit_binary_values);
if (pretty_print) if (pretty_print)
json->append(kPrettyPrintLineEnding); json->append(kPrettyPrintLineEnding);
} }
...@@ -51,7 +53,8 @@ JSONWriter::JSONWriter(bool pretty_print, std::string* json) ...@@ -51,7 +53,8 @@ JSONWriter::JSONWriter(bool pretty_print, std::string* json)
void JSONWriter::BuildJSONString(const Value* const node, void JSONWriter::BuildJSONString(const Value* const node,
int depth, int depth,
bool escape) { bool escape,
bool omit_binary_values) {
switch (node->GetType()) { switch (node->GetType()) {
case Value::TYPE_NULL: case Value::TYPE_NULL:
json_string_->append("null"); json_string_->append("null");
...@@ -122,16 +125,21 @@ void JSONWriter::BuildJSONString(const Value* const node, ...@@ -122,16 +125,21 @@ void JSONWriter::BuildJSONString(const Value* const node,
const ListValue* list = static_cast<const ListValue*>(node); const ListValue* list = static_cast<const ListValue*>(node);
for (size_t i = 0; i < list->GetSize(); ++i) { for (size_t i = 0; i < list->GetSize(); ++i) {
Value* value = NULL;
bool result = list->Get(i, &value);
DCHECK(result);
if (omit_binary_values && value->GetType() == Value::TYPE_BINARY) {
continue;
}
if (i != 0) { if (i != 0) {
json_string_->append(","); json_string_->append(",");
if (pretty_print_) if (pretty_print_)
json_string_->append(" "); json_string_->append(" ");
} }
Value* value = NULL; BuildJSONString(value, depth, escape, omit_binary_values);
bool result = list->Get(i, &value);
DCHECK(result);
BuildJSONString(value, depth, escape);
} }
if (pretty_print_) if (pretty_print_)
...@@ -151,16 +159,20 @@ void JSONWriter::BuildJSONString(const Value* const node, ...@@ -151,16 +159,20 @@ void JSONWriter::BuildJSONString(const Value* const node,
for (DictionaryValue::key_iterator key_itr = dict->begin_keys(); for (DictionaryValue::key_iterator key_itr = dict->begin_keys();
key_itr != dict->end_keys(); key_itr != dict->end_keys();
++key_itr) { ++key_itr) {
Value* value = NULL;
bool result = dict->GetWithoutPathExpansion(*key_itr, &value);
DCHECK(result);
if (omit_binary_values && value->GetType() == Value::TYPE_BINARY) {
continue;
}
if (key_itr != dict->begin_keys()) { if (key_itr != dict->begin_keys()) {
json_string_->append(","); json_string_->append(",");
if (pretty_print_) if (pretty_print_)
json_string_->append(kPrettyPrintLineEnding); json_string_->append(kPrettyPrintLineEnding);
} }
Value* value = NULL;
bool result = dict->GetWithoutPathExpansion(*key_itr, &value);
DCHECK(result);
if (pretty_print_) if (pretty_print_)
IndentLine(depth + 1); IndentLine(depth + 1);
AppendQuotedString(*key_itr); AppendQuotedString(*key_itr);
...@@ -169,7 +181,7 @@ void JSONWriter::BuildJSONString(const Value* const node, ...@@ -169,7 +181,7 @@ void JSONWriter::BuildJSONString(const Value* const node,
} else { } else {
json_string_->append(":"); json_string_->append(":");
} }
BuildJSONString(value, depth + 1, escape); BuildJSONString(value, depth + 1, escape, omit_binary_values);
} }
if (pretty_print_) { if (pretty_print_) {
...@@ -182,8 +194,15 @@ void JSONWriter::BuildJSONString(const Value* const node, ...@@ -182,8 +194,15 @@ void JSONWriter::BuildJSONString(const Value* const node,
break; break;
} }
case Value::TYPE_BINARY:
{
if (!omit_binary_values) {
NOTREACHED() << "Cannot serialize binary value.";
}
break;
}
default: default:
// TODO(jhughes): handle TYPE_BINARY
NOTREACHED() << "unknown json type"; NOTREACHED() << "unknown json type";
} }
} }
......
...@@ -17,6 +17,17 @@ class Value; ...@@ -17,6 +17,17 @@ class Value;
class BASE_EXPORT JSONWriter { class BASE_EXPORT JSONWriter {
public: public:
enum Options {
// Do not escape the string, preserving its UTF8 characters. It is useful
// if you can pass the resulting string to the JSON parser in binary form
// (as UTF8).
OPTIONS_DO_NOT_ESCAPE = 1 << 0,
// For values of binary type, the value (and key if within a dictionary)
// will be omitted from the output.
OPTIONS_OMIT_BINARY_VALUES = 1 << 1
};
// Given a root node, generates a JSON string and puts it into |json|. // Given a root node, generates a JSON string and puts it into |json|.
// If |pretty_print| is true, return a slightly nicer formated json string // If |pretty_print| is true, return a slightly nicer formated json string
// (pads with whitespace to help readability). If |pretty_print| is false, // (pads with whitespace to help readability). If |pretty_print| is false,
...@@ -27,13 +38,10 @@ class BASE_EXPORT JSONWriter { ...@@ -27,13 +38,10 @@ class BASE_EXPORT JSONWriter {
static void Write(const Value* const node, bool pretty_print, static void Write(const Value* const node, bool pretty_print,
std::string* json); std::string* json);
// Same as above, but has an option to not escape the string, preserving its // Same as above but with |options| which is a bunch of JSONWriter::Options
// UTF8 characters. It is useful if you can pass resulting string to the // bitwise ORed together.
// JSON parser in binary form (as UTF8). static void WriteWithOptions(const Value* const node, bool pretty_print,
static void WriteWithOptionalEscape(const Value* const node, int options, std::string* json);
bool pretty_print,
bool escape,
std::string* json);
// A static, constant JSON string representing an empty array. Useful // A static, constant JSON string representing an empty array. Useful
// for empty JSON argument passing. // for empty JSON argument passing.
...@@ -44,7 +52,8 @@ class BASE_EXPORT JSONWriter { ...@@ -44,7 +52,8 @@ class BASE_EXPORT JSONWriter {
// Called recursively to build the JSON string. Whe completed, value is // Called recursively to build the JSON string. Whe completed, value is
// json_string_ will contain the JSON. // json_string_ will contain the JSON.
void BuildJSONString(const Value* const node, int depth, bool escape); void BuildJSONString(const Value* const node, int depth, bool escape,
bool ignore_binary_values);
// Appends a quoted, escaped, version of (UTF-8) str to json_string_. // Appends a quoted, escaped, version of (UTF-8) str to json_string_.
void AppendQuotedString(const std::string& str); void AppendQuotedString(const std::string& str);
......
// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -93,6 +93,32 @@ TEST(JSONWriterTest, Writing) { ...@@ -93,6 +93,32 @@ TEST(JSONWriterTest, Writing) {
period_dict3.SetWithoutPathExpansion("a.b", Value::CreateIntegerValue(1)); period_dict3.SetWithoutPathExpansion("a.b", Value::CreateIntegerValue(1));
JSONWriter::Write(&period_dict3, false, &output_js); JSONWriter::Write(&period_dict3, false, &output_js);
ASSERT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js); ASSERT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
// Test ignoring binary values.
root = BinaryValue::CreateWithCopiedBuffer("asdf", 4);
JSONWriter::WriteWithOptions(root, false,
JSONWriter::OPTIONS_OMIT_BINARY_VALUES,
&output_js);
ASSERT_TRUE(output_js.empty());
delete root;
ListValue binary_list;
binary_list.Append(Value::CreateIntegerValue(5));
binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
binary_list.Append(Value::CreateIntegerValue(2));
JSONWriter::WriteWithOptions(&binary_list, false,
JSONWriter::OPTIONS_OMIT_BINARY_VALUES,
&output_js);
ASSERT_EQ("[5,2]", output_js);
DictionaryValue binary_dict;
binary_dict.Set("a", Value::CreateIntegerValue(5));
binary_dict.Set("b", BinaryValue::CreateWithCopiedBuffer("asdf", 4));
binary_dict.Set("c", Value::CreateIntegerValue(2));
JSONWriter::WriteWithOptions(&binary_dict, false,
JSONWriter::OPTIONS_OMIT_BINARY_VALUES,
&output_js);
ASSERT_EQ("{\"a\":5,\"c\":2}", output_js);
} }
} // namespace base } // namespace base
...@@ -1006,7 +1006,8 @@ std::string AboutStats(const std::string& query) { ...@@ -1006,7 +1006,8 @@ std::string AboutStats(const std::string& query) {
std::string data; std::string data;
if (query == "json" || query == kStringsJsPath) { if (query == "json" || query == kStringsJsPath) {
base::JSONWriter::WriteWithOptionalEscape(&root, true, false, &data); base::JSONWriter::WriteWithOptions(
&root, true, base::JSONWriter::OPTIONS_DO_NOT_ESCAPE, &data);
if (query == kStringsJsPath) if (query == kStringsJsPath)
data = "var templateData = " + data + ";"; data = "var templateData = " + data + ";";
} else if (query == "raw") { } else if (query == "raw") {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment