@@ -7,8 +7,31 @@ import upickle.core.{ArrVisitor, ObjVisitor, Visitor}
77
88import scala .collection .mutable
99
10+ object ValVisitor {
11+ final class InvalidUnicodeString extends RuntimeException (null , null , false , false )
12+
13+ def rejectUnpairedSurrogates (s : CharSequence ): Unit = {
14+ var i = 0
15+ val length = s.length
16+ while (i < length) {
17+ val c = s.charAt(i)
18+ if (Character .isHighSurrogate(c)) {
19+ if (i + 1 >= length || ! Character .isLowSurrogate(s.charAt(i + 1 ))) {
20+ throw new InvalidUnicodeString
21+ }
22+ i += 2
23+ } else if (Character .isLowSurrogate(c)) {
24+ throw new InvalidUnicodeString
25+ } else {
26+ i += 1
27+ }
28+ }
29+ }
30+ }
31+
1032/** Parse JSON directly into a literal `Val` */
11- class ValVisitor (pos : Position ) extends JsVisitor [Val , Val ] { self =>
33+ class ValVisitor (pos : Position , rejectUnpairedSurrogates : Boolean = false )
34+ extends JsVisitor [Val , Val ] { self =>
1235
1336 override def visitJsonableObject (length : Int , index : Int ): ObjVisitor [Val , Val ] =
1437 visitObject(length, index)
@@ -27,7 +50,10 @@ class ValVisitor(pos: Position) extends JsVisitor[Val, Val] { self =>
2750 var key : String = _
2851 def subVisitor : Visitor [? , ? ] = self
2952 def visitKey (index : Int ): upickle.core.StringVisitor .type = upickle.core.StringVisitor
30- def visitKeyValue (s : Any ): Unit = key = s.toString
53+ def visitKeyValue (s : Any ): Unit = {
54+ key = s.toString
55+ if (rejectUnpairedSurrogates) ValVisitor .rejectUnpairedSurrogates(key)
56+ }
3157 def visitValue (v : Val , index : Int ): Unit = {
3258 cache.put(key, v)
3359 allKeys.put(key, false )
@@ -52,5 +78,8 @@ class ValVisitor(pos: Position) extends JsVisitor[Val, Val] { self =>
5278 }
5379 )
5480
55- def visitString (s : CharSequence , index : Int ): Val = Val .Str (pos, s.toString)
81+ def visitString (s : CharSequence , index : Int ): Val = {
82+ if (rejectUnpairedSurrogates) ValVisitor .rejectUnpairedSurrogates(s)
83+ Val .Str (pos, s.toString)
84+ }
5685}
0 commit comments