-
Notifications
You must be signed in to change notification settings - Fork 0
/
encoder.go
114 lines (86 loc) · 2.04 KB
/
encoder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package json
import (
"unicode/utf8"
)
type (
Encoder struct{}
)
const hex = "0123456789abcdef"
var jsonStringSafe [2]uint64
func init() {
for b := byte(0x20); b < utf8.RuneSelf; b++ {
if b == '"' || b == '\\' {
continue
}
i, j := safeIJ(b)
jsonStringSafe[i] |= 1 << j
}
}
func (e *Encoder) AppendKey(w, s []byte) []byte {
w = append(w, '"')
w = append(w, s...)
w = append(w, '"')
return w
}
// EncodeString encodes string in a JSON compatible way.
func (e *Encoder) AppendString(w, s []byte) []byte {
w = append(w, '"')
w = e.AppendStringContent(w, s)
w = append(w, '"')
return w
}
// EncodeStringContent does the same as EncodeString but does not add quotes.
// It can be used to generate the string from multiple parts.
// Yet if a symbol designated to be escaped is split between parts
// it encodes each part of the symbol separately.
func (e *Encoder) AppendStringContent(w, s []byte) []byte {
done := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
if isSafeJSON(b) {
i++
continue
}
w = append(w, s[done:i]...)
switch b {
case '"', '\\', '/':
w = append(w, '\\', b)
case '\n':
w = append(w, '\\', 'n')
case '\r':
w = append(w, '\\', 'r')
case '\t':
w = append(w, '\\', 't')
// case '\f':
// w = append(w, '\\', 'f')
// case '\b':
// w = append(w, '\\', 'b')
default:
w = append(w, '\\', 'u', '0', '0', hex[b>>4&0xf], hex[b&0xf])
}
i++
done = i
continue
}
r, size := utf8.DecodeRune(s[i:])
if r == utf8.RuneError && size == 1 || r == '\u2028' || r == '\u2029' {
w = append(w, s[done:i]...)
w = append(w, '\\', 'u', hex[r>>12&0xf], hex[r>>8&0xf], hex[r>>4&0xf], hex[r&0xf])
// w = append(w, `\ufffd`...)
// w = append(w, '\\', 'u', '2', '0', 2, hex[r&0xf])
i += size
done = i
continue
}
i += size
}
w = append(w, s[done:]...)
return w
}
func safeIJ(b byte) (i, j int) {
return int(b) / 64, int(b) % 64
}
func isSafeJSON(b byte) bool {
i, j := safeIJ(b)
return jsonStringSafe[i]&(1<<j) != 0
}