Correctly encode special characters in JSON
Change-Id: Idc6ad9eb93b44ba5ba1ce4b830b51e404d53e1a7
diff --git a/elemental/src/elemental/json/impl/JsonUtil.java b/elemental/src/elemental/json/impl/JsonUtil.java
index c84fa75..e853e5e 100644
--- a/elemental/src/elemental/json/impl/JsonUtil.java
+++ b/elemental/src/elemental/json/impl/JsonUtil.java
@@ -188,7 +188,7 @@
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (isControlChar(c)) {
- toReturn.append(escapeStringAsUnicode(String.valueOf(c)));
+ toReturn.append(escapeCharAsUnicode(c));
} else {
toReturn.append(c);
}
@@ -233,7 +233,7 @@
break;
default:
if (isControlChar(c)) {
- toAppend = escapeStringAsUnicode(String.valueOf(c));
+ toAppend = escapeCharAsUnicode(c);
}
}
toReturn.append(toAppend);
@@ -285,11 +285,10 @@
/**
* Turn a single unicode character into a 32-bit unicode hex literal.
*/
- private static String escapeStringAsUnicode(String match) {
- String hexValue = Integer.toString(match.charAt(0), 16);
- hexValue = hexValue.length() > 4 ? hexValue.substring(hexValue.length() - 4)
- : hexValue;
- return "\\u0000" + hexValue;
+ private static String escapeCharAsUnicode(char toEscape) {
+ String hexValue = Integer.toString(toEscape, 16);
+ int padding = 4 - hexValue.length();
+ return "\\u" + ("0000".substring(0, padding)) + hexValue;
}
private static boolean isControlChar(char c) {
diff --git a/elemental/tests/elemental/json/JsonUtilTest.java b/elemental/tests/elemental/json/JsonUtilTest.java
index d9e2265..d331c2e 100755
--- a/elemental/tests/elemental/json/JsonUtilTest.java
+++ b/elemental/tests/elemental/json/JsonUtilTest.java
@@ -111,7 +111,7 @@
public void testEscapeControlChars() {
String unicodeString = "\u2060Test\ufeffis a test\u17b5";
- assertEquals("\\u00002060Test\\u0000feffis a test\\u000017b5",
+ assertEquals("\\u2060Test\\ufeffis a test\\u17b5",
JsonUtil.escapeControlChars(unicodeString));
}
@@ -142,8 +142,8 @@
public void testQuote() {
String badString = "\bThis\"is\ufeff\ta\\bad\nstring\u2029\u2029";
- assertEquals("\"\\bThis\\\"is\\u0000feff\\ta\\\\bad\\nstring"
- + "\\u00002029\\u00002029\"", JsonUtil.quote(badString));
+ assertEquals("\"\\bThis\\\"is\\ufeff\\ta\\\\bad\\nstring"
+ + "\\u2029\\u2029\"", JsonUtil.quote(badString));
}
public void testStringify() {
@@ -214,4 +214,48 @@
o.y = o.x + 1;
return o;
}-*/;
+
+ public void testQuoteCharacters() {
+ // See spec at https://tools.ietf.org/html/rfc7159
+ for (int i = 0; i < 0xffff; i++) {
+ String unencodedString = String.valueOf((char) i);
+ String res = JsonUtil.quote(unencodedString);
+ if (res.equals("\"" + unencodedString + "\"")) {
+ // passed through unescaped
+ if (i == 0x20 || i == 0x21 || (i >= 0x23 && i <= 0x5b)
+ || i >= 0x5d) {
+ // ok for %x20-21 / %x23-5B / %x5D-10FFFF
+ } else {
+ fail("Character " + i + " must be escaped in JSON");
+ }
+ } else {
+ // Was escaped, should be in format \\X or \\uXXXX
+ if (res.length() == 4) {
+ // "\\X"
+ char escapedChar = res.charAt(2);
+ // btnfr\"
+ if (escapedChar == 'b') {
+ assertEquals('\b',i);
+ } else if (escapedChar == 't') {
+ assertEquals('\t',i);
+ } else if (escapedChar == 'n') {
+ assertEquals('\n',i);
+ } else if (escapedChar == 'f') {
+ assertEquals('\f',i);
+ } else if (escapedChar == 'r') {
+ assertEquals('\r',i);
+ } else if (escapedChar == '"') {
+ assertEquals('"',i);
+ } else if (escapedChar == '\\') {
+ assertEquals('\\',i);
+ } else {
+ fail("Character" + i + " was unexpectedly escaped as "+escapedChar);
+ }
+ } else {
+ assertTrue("Character " + i + " was incorrectly encoded as " +
+ res,res.matches("\"\\\\u....\""));
+ }
+ }
+ }
+ }
}