diff --git a/decode_test.go b/decode_test.go index 1d9f47c..f7c4074 100644 --- a/decode_test.go +++ b/decode_test.go @@ -3931,3 +3931,16 @@ func TestIssue359(t *testing.T) { t.Errorf("unexpected result: %v", string(v)) } } + +func TestIssue364(t *testing.T) { + var v struct { + Description string `json:"description"` + } + err := json.Unmarshal([]byte(`{"description":"\uD83D\uDE87 Toledo is a metro station"}`), &v) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if v.Description != "🚇 Toledo is a metro station" { + t.Errorf("unexpected result: %v", v.Description) + } +} diff --git a/internal/decoder/string.go b/internal/decoder/string.go index a55ac55..dc0a010 100644 --- a/internal/decoder/string.go +++ b/internal/decoder/string.go @@ -386,6 +386,19 @@ func unescapeString(buf []byte) int { v3 := hexToInt[char(src, 4)] v4 := hexToInt[char(src, 5)] code := rune((v1 << 12) | (v2 << 8) | (v3 << 4) | v4) + if code >= 0xd800 && code < 0xdc00 && uintptr(unsafeAdd(src, 11)) < uintptr(end) { + if char(src, 6) == '\\' && char(src, 7) == 'u' { + v1 := hexToInt[char(src, 8)] + v2 := hexToInt[char(src, 9)] + v3 := hexToInt[char(src, 10)] + v4 := hexToInt[char(src, 11)] + lo := rune((v1 << 12) | (v2 << 8) | (v3 << 4) | v4) + if lo >= 0xdc00 && lo < 0xe000 { + code = (code-0xd800)<<10 | (lo - 0xdc00) + 0x10000 + src = unsafeAdd(src, 6) + } + } + } var b [utf8.UTFMax]byte n := utf8.EncodeRune(b[:], code) switch n {