فهرست منبع

Surrogates in JSON (#8238)

Aurel 6 سال پیش
والد
کامیت
16808145f5
2فایلهای تغییر یافته به همراه37 افزوده شده و 3 حذف شده
  1. 28 3
      std/haxe/format/JsonParser.hx
  2. 9 0
      tests/unit/src/unit/TestJson.hx

+ 28 - 3
std/haxe/format/JsonParser.hx

@@ -151,7 +151,15 @@ class JsonParser {
 
 	function parseString() {
 		var start = pos;
-		var buf = null;
+		var buf:StringBuf = null;
+		#if (target.unicode)
+		var prev = -1;
+		inline function cancelSurrogate() {
+			// invalid high surrogate (not followed by low surrogate)
+			buf.addChar(0xFFFD);
+			prev = -1;
+		}
+		#end
 		while( true ) {
 			var c = nextChar();
 			if( c == '"'.code )
@@ -162,6 +170,9 @@ class JsonParser {
 				}
 				buf.addSub(str,start, pos - start - 1);
 				c = nextChar();
+				#if (target.unicode)
+				if( c != "u".code && prev != -1 ) cancelSurrogate();
+				#end
 				switch( c ) {
 				case "r".code: buf.addChar("\r".code);
 				case "n".code: buf.addChar("\n".code);
@@ -170,7 +181,7 @@ class JsonParser {
 				case "f".code: buf.addChar(12);
 				case "/".code, '\\'.code, '"'.code: buf.addChar(c);
 				case 'u'.code:
-					var uc = Std.parseInt("0x" + str.substr(pos, 4));
+					var uc:Int = Std.parseInt("0x" + str.substr(pos, 4));
 					pos += 4;
 					#if !(target.unicode)
 					if( uc <= 0x7F )
@@ -189,7 +200,17 @@ class JsonParser {
 						buf.addChar(0x80 | (uc & 63));
 					}
 					#else
-					buf.addChar(uc);
+					if( prev != -1 ) {
+						if( uc < 0xDC00 || uc > 0xDFFF )
+							cancelSurrogate();
+						else {
+							buf.addChar(((prev - 0xD800) << 10) + (uc - 0xDC00) + 0x10000);
+							prev = -1;
+						}
+					} else if( uc >= 0xD800 && uc <= 0xDBFF )
+						prev = uc;
+					else
+						buf.addChar(uc);
 					#end
 				default:
 					throw "Invalid escape sequence \\" + String.fromCharCode(c) + " at position " + (pos - 1);
@@ -209,6 +230,10 @@ class JsonParser {
 			else if( StringTools.isEof(c) )
 				throw "Unclosed string";
 		}
+		#if (target.unicode)
+		if( prev != -1 )
+			cancelSurrogate();
+		#end
 		if (buf == null) {
 			return str.substr(start, pos - start - 1);
 		}

+ 9 - 0
tests/unit/src/unit/TestJson.hx

@@ -108,4 +108,13 @@ class TestJson extends Test {
 		eq( parsed.x, -4500 );
 		eq( parsed.y, 1.456 );
 	}
+
+	#if (!neko && (cpp && !cppia && !hxcpp_smart_strings))
+	function test8228() {
+		var strJson = haxe.Json.stringify("👽");
+		t(strJson == '"👽"' || strJson == '"\\ud83d\\udc7d"');
+		eq( haxe.Json.parse('"👽"'), "👽" );
+		eq( haxe.Json.parse('"\\ud83d\\udc7d"'), "👽" );
+	}
+	#end
 }