Skip to content

Commit 3b092fe

Browse files
committed
json: support \u escaping in strings
Fixes #73. R=rsc CC=golang-dev https://golang.org/cl/154072
1 parent ae33414 commit 3b092fe

File tree

2 files changed

+28
-12
lines changed

2 files changed

+28
-12
lines changed

src/pkg/json/generic_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ var jsontests = []string{
2121
`[1,2,"abc",null,true,false]`,
2222
`{}`,
2323
`{"a":1}`,
24+
`"q\u0302"`,
2425
}
2526

2627
func TestJson(t *testing.T) {

src/pkg/json/parse.go

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ func _UnHex(p string, r, l int) (v int, ok bool) {
4343
return v, true;
4444
}
4545

46+
func _ToHex(b []byte, rune int) {
47+
const hexDigits = "0123456789abcdef";
48+
b[0] = hexDigits[rune>>12&0xf];
49+
b[1] = hexDigits[rune>>8&0xf];
50+
b[2] = hexDigits[rune>>4&0xf];
51+
b[3] = hexDigits[rune&0xf];
52+
}
53+
4654
// Unquote unquotes the JSON-quoted string s,
4755
// returning a raw string t. If s is not a valid
4856
// JSON-quoted string, Unquote returns with ok set to false.
@@ -88,7 +96,7 @@ func Unquote(s string) (t string, ok bool) {
8896
w++;
8997
case 'u':
9098
r++;
91-
rune, ok := _UnHex(s, r, 4);
99+
rune, ok := _UnHex(s, r, r+4);
92100
if !ok {
93101
return
94102
}
@@ -122,46 +130,53 @@ func Unquote(s string) (t string, ok bool) {
122130
// Quote quotes the raw string s using JSON syntax,
123131
// so that Unquote(Quote(s)) = s, true.
124132
func Quote(s string) string {
125-
chr := make([]byte, utf8.UTFMax);
133+
chr := make([]byte, 6);
126134
chr0 := chr[0:1];
127135
b := new(bytes.Buffer);
128136
chr[0] = '"';
129137
b.Write(chr0);
130-
for i := 0; i < len(s); i++ {
138+
139+
for _, rune := range s {
131140
switch {
132-
case s[i] == '"' || s[i] == '\\':
141+
case rune == '"' || rune == '\\':
133142
chr[0] = '\\';
134-
chr[1] = s[i];
143+
chr[1] = byte(rune);
135144
b.Write(chr[0:2]);
136145

137-
case s[i] == '\b':
146+
case rune == '\b':
138147
chr[0] = '\\';
139148
chr[1] = 'b';
140149
b.Write(chr[0:2]);
141150

142-
case s[i] == '\f':
151+
case rune == '\f':
143152
chr[0] = '\\';
144153
chr[1] = 'f';
145154
b.Write(chr[0:2]);
146155

147-
case s[i] == '\n':
156+
case rune == '\n':
148157
chr[0] = '\\';
149158
chr[1] = 'n';
150159
b.Write(chr[0:2]);
151160

152-
case s[i] == '\r':
161+
case rune == '\r':
153162
chr[0] = '\\';
154163
chr[1] = 'r';
155164
b.Write(chr[0:2]);
156165

157-
case s[i] == '\t':
166+
case rune == '\t':
158167
chr[0] = '\\';
159168
chr[1] = 't';
160169
b.Write(chr[0:2]);
161170

162-
case 0x20 <= s[i] && s[i] < utf8.RuneSelf:
163-
chr[0] = s[i];
171+
case 0x20 <= rune && rune < utf8.RuneSelf:
172+
chr[0] = byte(rune);
164173
b.Write(chr0);
174+
175+
default:
176+
chr[0] = '\\';
177+
chr[1] = 'u';
178+
_ToHex(chr[2:6], rune);
179+
b.Write(chr);
165180
}
166181
}
167182
chr[0] = '"';

0 commit comments

Comments
 (0)