diff --git a/commons-core/src/main/scala/com/avsystem/commons/serialization/json/JsonStringInput.scala b/commons-core/src/main/scala/com/avsystem/commons/serialization/json/JsonStringInput.scala index 1dcd88b27..0e2204512 100644 --- a/commons-core/src/main/scala/com/avsystem/commons/serialization/json/JsonStringInput.scala +++ b/commons-core/src/main/scala/com/avsystem/commons/serialization/json/JsonStringInput.scala @@ -298,6 +298,7 @@ final class JsonReader(val json: String) { case 'r' => '\r' case 't' => '\t' case 'u' => ((readHex() << 12) + (readHex() << 8) + (readHex() << 4) + readHex()).toChar + case c => throw new ReadFailure(s"Unexpected character: '${c.toChar}'") } sb.append(unesc) plainStart = i @@ -305,8 +306,7 @@ final class JsonReader(val json: String) { } } if (sb != null) { - sb.append(json, plainStart, i - 1) - sb.toString + sb.append(json, plainStart, i - 1).toString } else { json.substring(plainStart, i - 1) } diff --git a/commons-core/src/main/scala/com/avsystem/commons/serialization/json/JsonStringOutput.scala b/commons-core/src/main/scala/com/avsystem/commons/serialization/json/JsonStringOutput.scala index 8a0390c60..c7054bdd6 100644 --- a/commons-core/src/main/scala/com/avsystem/commons/serialization/json/JsonStringOutput.scala +++ b/commons-core/src/main/scala/com/avsystem/commons/serialization/json/JsonStringOutput.scala @@ -23,27 +23,33 @@ trait BaseJsonOutput { var i = 0 var s = 0 while (i < str.length) { - val esc = str.charAt(i) match { - case '"' => "\\\"" - case '\\' => "\\\\" - case '\b' => "\\b" - case '\f' => "\\f" - case '\n' => "\\n" - case '\r' => "\\r" - case '\t' => "\\t" - case c if (ascii && c.toInt > 127) || Character.isISOControl(c) => - c.toInt.formatted("\\u%04x") - case _ => null + val ch = str.charAt(i) + val esc = ch match { + case '"' => '"' + case '\\' => '\\' + case '\b' => 'b' + case '\f' => 'f' + case '\n' => 'n' + case '\r' => 'r' + case '\t' => 't' + case _ => (if ((ascii && ch.toInt > 127) || Character.isISOControl(ch)) 1 else 0).toChar } - if (esc != null) { - builder.append(str, s, i).append(esc) + if (esc != 0) { + builder.append(str, s, i).append('\\') s = i + 1 + if (esc != 1) { + builder.append(esc) + } else { + builder.append('u').append(toHex((ch >> 12) & 15)).append(toHex((ch >> 8) & 15)) + .append(toHex((ch >> 4) & 15)).append(toHex(ch & 15)) + } } i += 1 } - builder.append(str, s, str.length) - builder.append('"') + builder.append(str, s, str.length).append('"') } + + protected final def toHex(nibble: Int): Char = (nibble + (if (nibble >= 10) 'a' - 10 else '0')).toChar } final class JsonStringOutput(builder: JStringBuilder, options: JsonOptions = JsonOptions.Default, depth: Int = 0) diff --git a/commons-core/src/test/scala/com/avsystem/commons/serialization/json/JsonStringInputOutputTest.scala b/commons-core/src/test/scala/com/avsystem/commons/serialization/json/JsonStringInputOutputTest.scala index a71bb869d..45c57ae7b 100644 --- a/commons-core/src/test/scala/com/avsystem/commons/serialization/json/JsonStringInputOutputTest.scala +++ b/commons-core/src/test/scala/com/avsystem/commons/serialization/json/JsonStringInputOutputTest.scala @@ -110,6 +110,7 @@ class JsonStringInputOutputTest extends FunSuite with SerializationTestUtils wit val options = JsonOptions(asciiOutput = true) assert(write[String]("ąę", options) == "\"\\u0105\\u0119\"") assert(read[String]("\"\\u0105\\u0119\"", options) == "ąę") + intercept[ReadFailure](read[String]("\"\\x0105\"")) } test("indentation") { diff --git a/version.sbt b/version.sbt index f82fae68e..c64c49aa7 100644 --- a/version.sbt +++ b/version.sbt @@ -1 +1 @@ -version in ThisBuild := "1.29.1" +version in ThisBuild := "1.29.2-SNAPSHOT"