summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorantrim@chromium.org <antrim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-11 11:52:22 +0000
committerantrim@chromium.org <antrim@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-11 11:52:22 +0000
commit11b366da9588a954343196434e00822aa3cf9b93 (patch)
tree0c8d3d6b521be4308c4f979ad19e1526ca65bc8e /base
parent3fa8fe590f29d504ce1284d5b4814c64861b4ab7 (diff)
downloadchromium_src-11b366da9588a954343196434e00822aa3cf9b93.zip
chromium_src-11b366da9588a954343196434e00822aa3cf9b93.tar.gz
chromium_src-11b366da9588a954343196434e00822aa3cf9b93.tar.bz2
Revert of https://codereview.chromium.org/100823007/
Reason for revert: This patchset breaks at least displayment of Russian localized strings on Chromeos login screen. TBR=mark@chromium.org,jshin@chromium.org,thakis@chromium.org,asanka@chromium.org,zea@chromium.org,bauerb@chromium.org,rsesek@chromium.org NOTREECHECKS=true NOTRY=true Review URL: https://codereview.chromium.org/106793004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240082 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/debug/trace_event_impl.cc2
-rw-r--r--base/json/json_value_serializer_unittest.cc35
-rw-r--r--base/json/json_writer.cc32
-rw-r--r--base/json/json_writer.h21
-rw-r--r--base/json/string_escape.cc147
-rw-r--r--base/json/string_escape.h62
-rw-r--r--base/json/string_escape_unittest.cc184
-rw-r--r--base/metrics/statistics_recorder.cc2
8 files changed, 181 insertions, 304 deletions
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index f9ff510..50bf342 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -662,7 +662,7 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
break;
case TRACE_VALUE_TYPE_STRING:
case TRACE_VALUE_TYPE_COPY_STRING:
- EscapeJSONString(value.as_string ? value.as_string : "NULL", true, out);
+ JsonDoubleQuote(value.as_string ? value.as_string : "NULL", true, out);
break;
default:
NOTREACHED() << "Don't know how to print this value";
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
index 44c0a57..314cd07 100644
--- a/base/json/json_value_serializer_unittest.cc
+++ b/base/json/json_value_serializer_unittest.cc
@@ -235,23 +235,22 @@ TEST(JSONValueSerializerTest, StringEscape) {
std::string all_chars_expected =
"\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r"
"\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017"
- "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"#$%&'()*+,"
- "-./0123456789:;\\u003C=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcde"
- "fghijklmnopqrstuvwxyz{|}~\x7F\xC2\x80\xC2\x81\xC2\x82\xC2\x83\xC2\x84"
- "\xC2\x85\xC2\x86\xC2\x87\xC2\x88\xC2\x89\xC2\x8A\xC2\x8B\xC2\x8C\xC2\x8D"
- "\xC2\x8E\xC2\x8F\xC2\x90\xC2\x91\xC2\x92\xC2\x93\xC2\x94\xC2\x95\xC2\x96"
- "\xC2\x97\xC2\x98\xC2\x99\xC2\x9A\xC2\x9B\xC2\x9C\xC2\x9D\xC2\x9E\xC2\x9F"
- "\xC2\xA0\xC2\xA1\xC2\xA2\xC2\xA3\xC2\xA4\xC2\xA5\xC2\xA6\xC2\xA7\xC2\xA8"
- "\xC2\xA9\xC2\xAA\xC2\xAB\xC2\xAC\xC2\xAD\xC2\xAE\xC2\xAF\xC2\xB0\xC2\xB1"
- "\xC2\xB2\xC2\xB3\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7\xC2\xB8\xC2\xB9\xC2\xBA"
- "\xC2\xBB\xC2\xBC\xC2\xBD\xC2\xBE\xC2\xBF\xC3\x80\xC3\x81\xC3\x82\xC3\x83"
- "\xC3\x84\xC3\x85\xC3\x86\xC3\x87\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B\xC3\x8C"
- "\xC3\x8D\xC3\x8E\xC3\x8F\xC3\x90\xC3\x91\xC3\x92\xC3\x93\xC3\x94\xC3\x95"
- "\xC3\x96\xC3\x97\xC3\x98\xC3\x99\xC3\x9A\xC3\x9B\xC3\x9C\xC3\x9D\xC3\x9E"
- "\xC3\x9F\xC3\xA0\xC3\xA1\xC3\xA2\xC3\xA3\xC3\xA4\xC3\xA5\xC3\xA6\xC3\xA7"
- "\xC3\xA8\xC3\xA9\xC3\xAA\xC3\xAB\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF\xC3\xB0"
- "\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7\xC3\xB8\xC3\xB9"
- "\xC3\xBA\xC3\xBB\xC3\xBC\xC3\xBD\xC3\xBE\xC3\xBF";
+ "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\""
+ "#$%&'()*+,-./0123456789:;\\u003C=\\u003E?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\"
+ "\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\\u007F\\u0080\\u0081\\u0082\\u0083"
+ "\\u0084\\u0085\\u0086\\u0087\\u0088\\u0089\\u008A\\u008B\\u008C\\u008D"
+ "\\u008E\\u008F\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097"
+ "\\u0098\\u0099\\u009A\\u009B\\u009C\\u009D\\u009E\\u009F\\u00A0\\u00A1"
+ "\\u00A2\\u00A3\\u00A4\\u00A5\\u00A6\\u00A7\\u00A8\\u00A9\\u00AA\\u00AB"
+ "\\u00AC\\u00AD\\u00AE\\u00AF\\u00B0\\u00B1\\u00B2\\u00B3\\u00B4\\u00B5"
+ "\\u00B6\\u00B7\\u00B8\\u00B9\\u00BA\\u00BB\\u00BC\\u00BD\\u00BE\\u00BF"
+ "\\u00C0\\u00C1\\u00C2\\u00C3\\u00C4\\u00C5\\u00C6\\u00C7\\u00C8\\u00C9"
+ "\\u00CA\\u00CB\\u00CC\\u00CD\\u00CE\\u00CF\\u00D0\\u00D1\\u00D2\\u00D3"
+ "\\u00D4\\u00D5\\u00D6\\u00D7\\u00D8\\u00D9\\u00DA\\u00DB\\u00DC\\u00DD"
+ "\\u00DE\\u00DF\\u00E0\\u00E1\\u00E2\\u00E3\\u00E4\\u00E5\\u00E6\\u00E7"
+ "\\u00E8\\u00E9\\u00EA\\u00EB\\u00EC\\u00ED\\u00EE\\u00EF\\u00F0\\u00F1"
+ "\\u00F2\\u00F3\\u00F4\\u00F5\\u00F6\\u00F7\\u00F8\\u00F9\\u00FA\\u00FB"
+ "\\u00FC\\u00FD\\u00FE\\u00FF";
std::string expected_output = "{\"all_chars\":\"" + all_chars_expected +
"\"}";
@@ -274,7 +273,7 @@ TEST(JSONValueSerializerTest, UnicodeStrings) {
string16 test(WideToUTF16(L"\x7F51\x9875"));
root.SetString("web", test);
- std::string expected = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}";
+ std::string expected = "{\"web\":\"\\u7F51\\u9875\"}";
std::string actual;
JSONStringValueSerializer serializer(&actual);
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index d600663..6a9cc6a 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -21,24 +21,28 @@ static const char kPrettyPrintLineEnding[] = "\r\n";
static const char kPrettyPrintLineEnding[] = "\n";
#endif
-// static
+/* static */
+const char* JSONWriter::kEmptyArray = "[]";
+
+/* static */
void JSONWriter::Write(const Value* const node, std::string* json) {
WriteWithOptions(node, 0, json);
}
-// static
+/* static */
void JSONWriter::WriteWithOptions(const Value* const node, int options,
std::string* json) {
json->clear();
// Is there a better way to estimate the size of the output?
json->reserve(1024);
+ bool escape = !(options & OPTIONS_DO_NOT_ESCAPE);
bool omit_binary_values = !!(options & OPTIONS_OMIT_BINARY_VALUES);
bool omit_double_type_preservation =
!!(options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION);
bool pretty_print = !!(options & OPTIONS_PRETTY_PRINT);
- JSONWriter writer(omit_binary_values, omit_double_type_preservation,
+ JSONWriter writer(escape, omit_binary_values, omit_double_type_preservation,
pretty_print, json);
writer.BuildJSONString(node, 0);
@@ -46,10 +50,11 @@ void JSONWriter::WriteWithOptions(const Value* const node, int options,
json->append(kPrettyPrintLineEnding);
}
-JSONWriter::JSONWriter(bool omit_binary_values,
+JSONWriter::JSONWriter(bool escape, bool omit_binary_values,
bool omit_double_type_preservation, bool pretty_print,
std::string* json)
- : omit_binary_values_(omit_binary_values),
+ : escape_(escape),
+ omit_binary_values_(omit_binary_values),
omit_double_type_preservation_(omit_double_type_preservation),
pretty_print_(pretty_print),
json_string_(json) {
@@ -118,7 +123,11 @@ void JSONWriter::BuildJSONString(const Value* const node, int depth) {
std::string value;
bool result = node->GetAsString(&value);
DCHECK(result);
- EscapeJSONString(value, true, json_string_);
+ if (escape_) {
+ JsonDoubleQuote(UTF8ToUTF16(value), true, json_string_);
+ } else {
+ JsonDoubleQuote(value, true, json_string_);
+ }
break;
}
@@ -160,7 +169,7 @@ void JSONWriter::BuildJSONString(const Value* const node, int depth) {
json_string_->append(kPrettyPrintLineEnding);
const DictionaryValue* dict =
- static_cast<const DictionaryValue*>(node);
+ static_cast<const DictionaryValue*>(node);
bool first_entry = true;
for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
itr.Advance(), first_entry = false) {
@@ -177,8 +186,7 @@ void JSONWriter::BuildJSONString(const Value* const node, int depth) {
if (pretty_print_)
IndentLine(depth + 1);
-
- EscapeJSONString(itr.key(), true, json_string_);
+ AppendQuotedString(itr.key());
if (pretty_print_) {
json_string_->append(": ");
} else {
@@ -210,6 +218,12 @@ void JSONWriter::BuildJSONString(const Value* const node, int depth) {
}
}
+void JSONWriter::AppendQuotedString(const std::string& str) {
+ // TODO(viettrungluu): |str| is UTF-8, not ASCII, so to properly escape it we
+ // have to convert it to UTF-16. This round-trip is suboptimal.
+ JsonDoubleQuote(UTF8ToUTF16(str), true, json_string_);
+}
+
void JSONWriter::IndentLine(int depth) {
// It may be faster to keep an indent string so we don't have to keep
// reallocating.
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
index e4a143c..94052c8 100644
--- a/base/json/json_writer.h
+++ b/base/json/json_writer.h
@@ -17,19 +17,24 @@ class Value;
class BASE_EXPORT JSONWriter {
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 << 0,
+ OPTIONS_OMIT_BINARY_VALUES = 1 << 1,
// This option instructs the writer to write doubles that have no fractional
// part as a normal integer (i.e., without using exponential notation
// or appending a '.0') as long as the value is within the range of a
// 64-bit int.
- OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 1,
+ OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 2,
// Return a slightly nicer formatted json string (pads with whitespace to
// help with readability).
- OPTIONS_PRETTY_PRINT = 1 << 2,
+ OPTIONS_PRETTY_PRINT = 1 << 3
};
// Given a root node, generates a JSON string and puts it into |json|.
@@ -43,8 +48,12 @@ class BASE_EXPORT JSONWriter {
static void WriteWithOptions(const Value* const node, int options,
std::string* json);
+ // A static, constant JSON string representing an empty array. Useful
+ // for empty JSON argument passing.
+ static const char* kEmptyArray;
+
private:
- JSONWriter(bool omit_binary_values,
+ JSONWriter(bool escape, bool omit_binary_values,
bool omit_double_type_preservation, bool pretty_print,
std::string* json);
@@ -52,9 +61,13 @@ class BASE_EXPORT JSONWriter {
// json_string_ will contain the JSON.
void BuildJSONString(const Value* const node, int depth);
+ // Appends a quoted, escaped, version of (UTF-8) str to json_string_.
+ void AppendQuotedString(const std::string& str);
+
// Adds space to json_string_ for the indent level.
void IndentLine(int depth);
+ bool escape_;
bool omit_binary_values_;
bool omit_double_type_preservation_;
bool pretty_print_;
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
index a3b0735..10ea670 100644
--- a/base/json/string_escape.cc
+++ b/base/json/string_escape.cc
@@ -8,56 +8,40 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversion_utils.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/third_party/icu/icu_utf.h"
namespace base {
namespace {
-// Format string for printing a \uXXXX escape sequence.
-const char kU16EscapeFormat[] = "\\u%04X";
-
-// The code point to output for an invalid input code unit.
-const uint32 kReplacementCodePoint = 0xFFFD;
-
-// Used below in EscapeSpecialCodePoint().
-COMPILE_ASSERT('<' == 0x3C, less_than_sign_is_0x3c);
-
-// Try to escape the |code_point| if it is a known special character. If
-// successful, returns true and appends the escape sequence to |dest|. This
-// isn't required by the spec, but it's more readable by humans.
-bool EscapeSpecialCodePoint(uint32 code_point, std::string* dest) {
+// Try to escape |c| as a "SingleEscapeCharacter" (\n, etc). If successful,
+// returns true and appends the escape sequence to |dst|. This isn't required
+// by the spec, but it's more readable by humans than the \uXXXX alternatives.
+template<typename CHAR>
+static bool JsonSingleEscapeChar(const CHAR c, std::string* dst) {
// WARNING: if you add a new case here, you need to update the reader as well.
// Note: \v is in the reader, but not here since the JSON spec doesn't
// allow it.
- switch (code_point) {
+ switch (c) {
case '\b':
- dest->append("\\b");
+ dst->append("\\b");
break;
case '\f':
- dest->append("\\f");
+ dst->append("\\f");
break;
case '\n':
- dest->append("\\n");
+ dst->append("\\n");
break;
case '\r':
- dest->append("\\r");
+ dst->append("\\r");
break;
case '\t':
- dest->append("\\t");
+ dst->append("\\t");
break;
case '\\':
- dest->append("\\\\");
+ dst->append("\\\\");
break;
case '"':
- dest->append("\\\"");
- break;
- // Escape < to prevent script execution; escaping > is not necessary and
- // not doing so save a few bytes.
- case '<':
- dest->append("\\u003C");
+ dst->append("\\\"");
break;
default:
return false;
@@ -65,90 +49,57 @@ bool EscapeSpecialCodePoint(uint32 code_point, std::string* dest) {
return true;
}
-template <typename S>
-bool EscapeJSONStringImpl(const S& str, bool put_in_quotes, std::string* dest) {
- bool did_replacement = false;
-
+template <class STR>
+void JsonDoubleQuoteT(const STR& str,
+ bool put_in_quotes,
+ std::string* dst) {
if (put_in_quotes)
- dest->push_back('"');
-
- // Casting is necessary because ICU uses int32. Try and do so safely.
- CHECK_LE(str.length(), static_cast<size_t>(kint32max));
- const int32 length = static_cast<int32>(str.length());
-
- for (int32 i = 0; i < length; ++i) {
- uint32 code_point;
- if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point)) {
- code_point = kReplacementCodePoint;
- did_replacement = true;
+ dst->push_back('"');
+
+ for (typename STR::const_iterator it = str.begin(); it != str.end(); ++it) {
+ typename ToUnsigned<typename STR::value_type>::Unsigned c = *it;
+ if (!JsonSingleEscapeChar(c, dst)) {
+ if (c < 32 || c > 126 || c == '<' || c == '>') {
+ // 1. Escaping <, > to prevent script execution.
+ // 2. Technically, we could also pass through c > 126 as UTF8, but this
+ // is also optional. It would also be a pain to implement here.
+ unsigned int as_uint = static_cast<unsigned int>(c);
+ base::StringAppendF(dst, "\\u%04X", as_uint);
+ } else {
+ unsigned char ascii = static_cast<unsigned char>(*it);
+ dst->push_back(ascii);
+ }
}
-
- if (EscapeSpecialCodePoint(code_point, dest))
- continue;
-
- // Escape non-printing characters.
- if (code_point < 32)
- base::StringAppendF(dest, kU16EscapeFormat, code_point);
- else
- WriteUnicodeCharacter(code_point, dest);
}
if (put_in_quotes)
- dest->push_back('"');
-
- return !did_replacement;
+ dst->push_back('"');
}
} // namespace
-bool EscapeJSONString(const StringPiece& str,
- bool put_in_quotes,
- std::string* dest) {
- return EscapeJSONStringImpl(str, put_in_quotes, dest);
+void JsonDoubleQuote(const StringPiece& str,
+ bool put_in_quotes,
+ std::string* dst) {
+ JsonDoubleQuoteT(str, put_in_quotes, dst);
}
-bool EscapeJSONString(const StringPiece16& str,
- bool put_in_quotes,
- std::string* dest) {
- return EscapeJSONStringImpl(str, put_in_quotes, dest);
-}
-
-std::string GetQuotedJSONString(const StringPiece& str) {
- std::string dest;
- bool ok = EscapeJSONStringImpl(str, true, &dest);
- DCHECK(ok);
- return dest;
+std::string GetDoubleQuotedJson(const StringPiece& str) {
+ std::string dst;
+ JsonDoubleQuote(str, true, &dst);
+ return dst;
}
-std::string GetQuotedJSONString(const StringPiece16& str) {
- std::string dest;
- bool ok = EscapeJSONStringImpl(str, true, &dest);
- DCHECK(ok);
- return dest;
+void JsonDoubleQuote(const StringPiece16& str,
+ bool put_in_quotes,
+ std::string* dst) {
+ JsonDoubleQuoteT(str, put_in_quotes, dst);
}
-std::string EscapeBytesAsInvalidJSONString(const StringPiece& str,
- bool put_in_quotes) {
- std::string dest;
-
- if (put_in_quotes)
- dest.push_back('"');
-
- for (StringPiece::const_iterator it = str.begin(); it != str.end(); ++it) {
- ToUnsigned<StringPiece::value_type>::Unsigned c = *it;
- if (EscapeSpecialCodePoint(c, &dest))
- continue;
-
- if (c < 32 || c > 126)
- base::StringAppendF(&dest, kU16EscapeFormat, c);
- else
- dest.push_back(*it);
- }
-
- if (put_in_quotes)
- dest.push_back('"');
-
- return dest;
+std::string GetDoubleQuotedJson(const StringPiece16& str) {
+ std::string dst;
+ JsonDoubleQuote(str, true, &dst);
+ return dst;
}
} // namespace base
diff --git a/base/json/string_escape.h b/base/json/string_escape.h
index b66b7e5..0f16f59 100644
--- a/base/json/string_escape.h
+++ b/base/json/string_escape.h
@@ -1,8 +1,8 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
-// This file defines utility functions for escaping strings suitable for JSON.
+//
+// This file defines utility functions for escaping strings.
#ifndef BASE_JSON_STRING_ESCAPE_H_
#define BASE_JSON_STRING_ESCAPE_H_
@@ -14,46 +14,24 @@
namespace base {
-// Appends to |dest| an escaped version of |str|. Valid UTF-8 code units will
-// pass through from the input to the output. Invalid code units will be
-// replaced with the U+FFFD replacement character. This function returns true
-// if no replacement was necessary and false if there was a lossy replacement.
-// On return, |dest| will contain a valid UTF-8 JSON string.
-//
-// Non-printing control characters will be escaped as \uXXXX sequences for
-// readability.
-//
-// If |put_in_quotes| is true, then a leading and trailing double-quote mark
-// will be appended to |dest| as well.
-BASE_EXPORT bool EscapeJSONString(const StringPiece& str,
- bool put_in_quotes,
- std::string* dest);
-
-// Performs a similar function to the UTF-8 StringPiece version above,
-// converting UTF-16 code units to UTF-8 code units and escaping non-printing
-// control characters. On return, |dest| will contain a valid UTF-8 JSON string.
-BASE_EXPORT bool EscapeJSONString(const StringPiece16& str,
- bool put_in_quotes,
- std::string* dest);
-
-// Helper functions that wrap the above two functions but return the value
-// instead of appending. |put_in_quotes| is always true.
-BASE_EXPORT std::string GetQuotedJSONString(const StringPiece& str);
-BASE_EXPORT std::string GetQuotedJSONString(const StringPiece16& str);
-
-// Given an arbitrary byte string |str|, this will escape all non-ASCII bytes
-// as \uXXXX escape sequences. This function is *NOT* meant to be used with
-// Unicode strings and does not validate |str| as one.
-//
-// CAVEAT CALLER: The output of this function may not be valid JSON, since
-// JSON requires escape sequences to be valid UTF-16 code units. This output
-// will be mangled if passed to to the base::JSONReader, since the reader will
-// interpret it as UTF-16 and convert it to UTF-8.
-//
-// The output of this function takes the *appearance* of JSON but is not in
-// fact valid according to RFC 4627.
-BASE_EXPORT std::string EscapeBytesAsInvalidJSONString(const StringPiece& str,
- bool put_in_quotes);
+// Escape |str| appropriately for a JSON string literal, _appending_ the
+// result to |dst|. This will create unicode escape sequences (\uXXXX).
+// If |put_in_quotes| is true, the result will be surrounded in double quotes.
+// The outputted literal, when interpreted by the browser, should result in a
+// javascript string that is identical and the same length as the input |str|.
+BASE_EXPORT void JsonDoubleQuote(const StringPiece& str,
+ bool put_in_quotes,
+ std::string* dst);
+
+// Same as above, but always returns the result double quoted.
+BASE_EXPORT std::string GetDoubleQuotedJson(const StringPiece& str);
+
+BASE_EXPORT void JsonDoubleQuote(const StringPiece16& str,
+ bool put_in_quotes,
+ std::string* dst);
+
+// Same as above, but always returns the result double quoted.
+BASE_EXPORT std::string GetDoubleQuotedJson(const StringPiece16& str);
} // namespace base
diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc
index 7d82f9b..f921994 100644
--- a/base/json/string_escape_unittest.cc
+++ b/base/json/string_escape_unittest.cc
@@ -1,182 +1,104 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/json/string_escape.h"
-
-#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
-TEST(JSONStringEscapeTest, EscapeUTF8) {
- const struct {
- const char* to_escape;
- const char* escaped;
- } cases[] = {
- {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
- {"a\b\f\n\r\t\v\1\\.\"z",
- "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
- {"b\x0f\x7f\xf0\xff!", // \xf0\xff is not a valid UTF-8 unit.
- "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"},
- {"c<>d", "c\\u003C>d"},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- const char* in_ptr = cases[i].to_escape;
- std::string in_str = in_ptr;
+namespace {
- std::string out;
- EscapeJSONString(in_ptr, false, &out);
- EXPECT_EQ(std::string(cases[i].escaped), out);
- EXPECT_TRUE(IsStringUTF8(out));
+const struct json_narrow_test_data {
+ const char* to_escape;
+ const char* escaped;
+} json_narrow_cases[] = {
+ {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
+ {"a\b\f\n\r\t\v\1\\.\"z",
+ "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
+ {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
+ {"c<>d", "c\\u003C\\u003Ed"},
+};
+} // namespace
+
+TEST(StringEscapeTest, JsonDoubleQuoteNarrow) {
+ for (size_t i = 0; i < arraysize(json_narrow_cases); ++i) {
+ const char* in_ptr = json_narrow_cases[i].to_escape;
+ std::string in_str = in_ptr;
+ std::string out;
+ JsonDoubleQuote(in_ptr, false, &out);
+ EXPECT_EQ(std::string(json_narrow_cases[i].escaped), out);
out.erase();
- bool convert_ok = EscapeJSONString(in_str, false, &out);
- EXPECT_EQ(std::string(cases[i].escaped), out);
- EXPECT_TRUE(IsStringUTF8(out));
-
- if (convert_ok) {
- std::string fooout = GetQuotedJSONString(in_str);
- EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout);
- EXPECT_TRUE(IsStringUTF8(out));
- }
+ JsonDoubleQuote(in_str, false, &out);
+ EXPECT_EQ(std::string(json_narrow_cases[i].escaped), out);
}
- std::string in = cases[0].to_escape;
+ std::string in = json_narrow_cases[0].to_escape;
std::string out;
- EscapeJSONString(in, false, &out);
- EXPECT_TRUE(IsStringUTF8(out));
+ JsonDoubleQuote(in, false, &out);
// test quoting
std::string out_quoted;
- EscapeJSONString(in, true, &out_quoted);
+ JsonDoubleQuote(in, true, &out_quoted);
EXPECT_EQ(out.length() + 2, out_quoted.length());
EXPECT_EQ(out_quoted.find(out), 1U);
- EXPECT_TRUE(IsStringUTF8(out_quoted));
// now try with a NULL in the string
std::string null_prepend = "test";
null_prepend.push_back(0);
in = null_prepend + in;
std::string expected = "test\\u0000";
- expected += cases[0].escaped;
+ expected += json_narrow_cases[0].escaped;
out.clear();
- EscapeJSONString(in, false, &out);
+ JsonDoubleQuote(in, false, &out);
EXPECT_EQ(expected, out);
- EXPECT_TRUE(IsStringUTF8(out));
}
-TEST(JSONStringEscapeTest, EscapeUTF16) {
- const struct {
- const wchar_t* to_escape;
- const char* escaped;
- } cases[] = {
- {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"},
- {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
- {L"a\b\f\n\r\t\v\1\\.\"z",
- "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
- {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
- {L"c<>d", "c\\u003C>d"},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- string16 in = WideToUTF16(cases[i].to_escape);
+namespace {
- std::string out;
- EscapeJSONString(in, false, &out);
- EXPECT_EQ(std::string(cases[i].escaped), out);
- EXPECT_TRUE(IsStringUTF8(out));
+const struct json_wide_test_data {
+ const wchar_t* to_escape;
+ const char* escaped;
+} json_wide_cases[] = {
+ {L"b\uffb1\u00ff", "b\\uFFB1\\u00FF"},
+ {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
+ {L"a\b\f\n\r\t\v\1\\.\"z",
+ "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
+ {L"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
+ {L"c<>d", "c\\u003C\\u003Ed"},
+};
- out = GetQuotedJSONString(in);
- EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", out);
- EXPECT_TRUE(IsStringUTF8(out));
+} // namespace
+
+TEST(StringEscapeTest, JsonDoubleQuoteWide) {
+ for (size_t i = 0; i < arraysize(json_wide_cases); ++i) {
+ std::string out;
+ string16 in = WideToUTF16(json_wide_cases[i].to_escape);
+ JsonDoubleQuote(in, false, &out);
+ EXPECT_EQ(std::string(json_wide_cases[i].escaped), out);
}
- string16 in = WideToUTF16(cases[0].to_escape);
+ string16 in = WideToUTF16(json_wide_cases[0].to_escape);
std::string out;
- EscapeJSONString(in, false, &out);
- EXPECT_TRUE(IsStringUTF8(out));
+ JsonDoubleQuote(in, false, &out);
// test quoting
std::string out_quoted;
- EscapeJSONString(in, true, &out_quoted);
+ JsonDoubleQuote(in, true, &out_quoted);
EXPECT_EQ(out.length() + 2, out_quoted.length());
EXPECT_EQ(out_quoted.find(out), 1U);
- EXPECT_TRUE(IsStringUTF8(out));
// now try with a NULL in the string
string16 null_prepend = WideToUTF16(L"test");
null_prepend.push_back(0);
in = null_prepend + in;
std::string expected = "test\\u0000";
- expected += cases[0].escaped;
+ expected += json_wide_cases[0].escaped;
out.clear();
- EscapeJSONString(in, false, &out);
+ JsonDoubleQuote(in, false, &out);
EXPECT_EQ(expected, out);
- EXPECT_TRUE(IsStringUTF8(out));
-}
-
-TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) {
- {
- // {a, U+10300, !}, SMP.
- string16 test;
- test.push_back('a');
- test.push_back(0xD800);
- test.push_back(0xDF00);
- test.push_back('!');
- std::string actual;
- EXPECT_TRUE(EscapeJSONString(test, false, &actual));
- EXPECT_EQ("a\xF0\x90\x8C\x80!", actual);
- }
- {
- // {U+20021, U+2002B}, SIP.
- string16 test;
- test.push_back(0xD840);
- test.push_back(0xDC21);
- test.push_back(0xD840);
- test.push_back(0xDC2B);
- std::string actual;
- EXPECT_TRUE(EscapeJSONString(test, false, &actual));
- EXPECT_EQ("\xF0\xA0\x80\xA1\xF0\xA0\x80\xAB", actual);
- }
- {
- // {?, U+D800, @}, lone surrogate.
- string16 test;
- test.push_back('?');
- test.push_back(0xD800);
- test.push_back('@');
- std::string actual;
- EXPECT_FALSE(EscapeJSONString(test, false, &actual));
- EXPECT_EQ("?\xEF\xBF\xBD@", actual);
- }
-}
-
-TEST(JSONStringEscapeTest, EscapeBytes) {
- const struct {
- const char* to_escape;
- const char* escaped;
- } cases[] = {
- {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
- {"\xe5\xc4\x4f\x05\xb6\xfd\0", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"},
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::string in = std::string(cases[i].to_escape);
- EXPECT_FALSE(IsStringUTF8(in));
-
- EXPECT_EQ(std::string(cases[i].escaped),
- EscapeBytesAsInvalidJSONString(in, false));
- EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"",
- EscapeBytesAsInvalidJSONString(in, true));
- }
-
- const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' };
- std::string in(kEmbedNull, ARRAYSIZE_UNSAFE(kEmbedNull));
- EXPECT_FALSE(IsStringUTF8(in));
- EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"),
- EscapeBytesAsInvalidJSONString(in, false));
}
} // namespace base
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 62617c5..2753c0b2 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -172,7 +172,7 @@ std::string StatisticsRecorder::ToJSON(const std::string& query) {
std::string output("{");
if (!query.empty()) {
output += "\"query\":";
- EscapeJSONString(query, true, &output);
+ JsonDoubleQuote(query, true, &output);
output += ",";
}