diff --git a/src/main/java/com/github/underscore/Xml.java b/src/main/java/com/github/underscore/Xml.java
index 793da57c..651fd917 100644
--- a/src/main/java/com/github/underscore/Xml.java
+++ b/src/main/java/com/github/underscore/Xml.java
@@ -1045,9 +1045,9 @@ private static void escape(String s, StringBuilder sb) {
|| ch >= '\u007F' && ch <= '\u009F'
|| ch >= '\u2000' && ch <= '\u20FF') {
String ss = Integer.toHexString(ch);
- sb.append("");
+ sb.append("\\x");
sb.append("0".repeat(4 - ss.length()));
- sb.append(ss.toUpperCase()).append(";");
+ sb.append(ss.toUpperCase());
} else {
sb.append(ch);
}
@@ -1101,7 +1101,28 @@ private static int translate(
}
}
}
- return 0;
+ return translateBinary(input, index, builder);
+ }
+
+ static int translateBinary(
+ final CharSequence input, final int index, final StringBuilder builder) {
+ final int length = input.length();
+ if (index + 5 >= length) {
+ return 0;
+ }
+ if (input.charAt(index) != '\\' || input.charAt(index + 1) != 'x') {
+ return 0;
+ }
+ int value = 0;
+ for (int i = index + 2; i < index + 6; i++) {
+ final int digit = Character.digit(input.charAt(i), 16);
+ if (digit < 0) {
+ return 0;
+ }
+ value = (value << 4) | digit;
+ }
+ builder.append((char) value);
+ return 6;
}
public static String getMapKey(Object map) {
@@ -1283,7 +1304,8 @@ private static Object getValue(final String name, final Object value, final From
} else {
localValue = value;
}
- return localValue instanceof String && name.startsWith("-")
+ return localValue instanceof String
+ && (name.startsWith("-") || ((String) localValue).contains("\\x"))
? XmlValue.unescape((String) localValue)
: localValue;
}
diff --git a/src/test/java/com/github/underscore/LodashTest.java b/src/test/java/com/github/underscore/LodashTest.java
index bf1fbe9b..1b08d81c 100644
--- a/src/test/java/com/github/underscore/LodashTest.java
+++ b/src/test/java/com/github/underscore/LodashTest.java
@@ -1152,6 +1152,14 @@ void xmpToJson6() {
+ ""));
}
+ @Test
+ void xmlToJson7() {
+ assertEquals(
+ "{\n \"debug\": \"\\u0001\"\n}",
+ U.xmlToJson(
+ "\n\\x0001"));
+ }
+
@Test
void xmlToJsonMinimum() {
assertEquals(
diff --git a/src/test/java/com/github/underscore/StringTest.java b/src/test/java/com/github/underscore/StringTest.java
index 88458ed6..e066e0e2 100644
--- a/src/test/java/com/github/underscore/StringTest.java
+++ b/src/test/java/com/github/underscore/StringTest.java
@@ -1197,14 +1197,14 @@ void escapeXml() {
assertEquals("
", Xml.XmlValue.escape("\r"));
assertEquals("\t", Xml.XmlValue.escape("\t"));
assertEquals("/", Xml.XmlValue.escape("/"));
- assertEquals("", Xml.XmlValue.escape("\u0000"));
- assertEquals("", Xml.XmlValue.escape("\u001F"));
+ assertEquals("\\x0000", Xml.XmlValue.escape("\u0000"));
+ assertEquals("\\x001F", Xml.XmlValue.escape("\u001F"));
assertEquals("\u0020", Xml.XmlValue.escape("\u0020"));
- assertEquals("", Xml.XmlValue.escape("\u007F"));
- assertEquals("", Xml.XmlValue.escape("\u009F"));
+ assertEquals("\\x007F", Xml.XmlValue.escape("\u007F"));
+ assertEquals("\\x009F", Xml.XmlValue.escape("\u009F"));
assertEquals("\u00A0", Xml.XmlValue.escape("\u00A0"));
- assertEquals(" ", Xml.XmlValue.escape("\u2000"));
- assertEquals("", Xml.XmlValue.escape("\u20FF"));
+ assertEquals("\\x2000", Xml.XmlValue.escape("\u2000"));
+ assertEquals("\\x20FF", Xml.XmlValue.escape("\u20FF"));
assertEquals("\u2100", Xml.XmlValue.escape("\u2100"));
assertEquals("\uFFFF", Xml.XmlValue.escape("\uFFFF"));
}
@@ -1219,6 +1219,96 @@ void unescapeXml() {
assertEquals("<", Xml.XmlValue.unescape("<"));
assertEquals(">", Xml.XmlValue.unescape(">"));
assertEquals(""", Xml.XmlValue.unescape("""));
+ assertEquals("\u20FF", Xml.XmlValue.unescape("\\x20FF"));
+ assertEquals("\u0000", Xml.XmlValue.unescape("\\x0000"));
+ assertEquals("\u001F", Xml.XmlValue.unescape("\\x001F"));
+ }
+
+ @Test
+ void translateBinary() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("\\x0041", 0, builder);
+ assertEquals(6, result);
+ assertEquals("A", builder.toString());
+ }
+
+ @Test
+ void translateBinary2() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("a\\x0041", 1, builder);
+ assertEquals(6, result);
+ assertEquals("A", builder.toString());
+ }
+
+ @Test
+ void translateBinary3() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("abc", 0, builder);
+ assertEquals(0, result);
+ assertEquals("", builder.toString());
+ }
+
+ @Test
+ void translateBinary4() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("\\u0041", 0, builder);
+ assertEquals(0, result);
+ assertEquals("", builder.toString());
+ }
+
+ @Test
+ void translateBinary5() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("\\x00G1", 0, builder);
+ assertEquals(0, result);
+ assertEquals("", builder.toString());
+ }
+
+ @Test
+ void translateBinary6() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("\\x041", 0, builder);
+ assertEquals(0, result);
+ assertEquals("", builder.toString());
+ }
+
+ @Test
+ void translateBinary7() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("\\x0000", 0, builder);
+ assertEquals(6, result);
+ assertEquals(1, builder.length());
+ assertEquals(0, builder.charAt(0));
+ }
+
+ @SuppressWarnings("java:S5976")
+ @Test
+ void translateBinary8() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("\\x1234", 0, builder);
+ assertEquals(6, result);
+ assertEquals(1, builder.length());
+ assertEquals('\u1234', builder.charAt(0));
+ }
+
+ @SuppressWarnings("java:S5976")
+ @Test
+ void translateBinary9() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("\\xFFFF", 0, builder);
+ assertEquals(6, result);
+ assertEquals(1, builder.length());
+ assertEquals('\uFFFF', builder.charAt(0));
+ }
+
+ @SuppressWarnings("java:S5976")
+ @Test
+ void translateBinary10() {
+ StringBuilder builder = new StringBuilder();
+ int result = Xml.XmlValue.translateBinary("\\x00af", 0, builder);
+ assertEquals(6, result);
+ assertEquals(1, builder.length());
+ assertEquals('\u00AF', builder.charAt(0));
}
@Test
@@ -1510,6 +1600,16 @@ void testXmlDecodeCyrillic() {
U.toXml((List