...
1 package logfmt
2
3 import (
4 "bytes"
5 "io"
6 "strconv"
7 "sync"
8 "unicode"
9 "unicode/utf16"
10 "unicode/utf8"
11 )
12
13
14
15
16
17
18
19 var hex = "0123456789abcdef"
20
21 var bufferPool = sync.Pool{
22 New: func() interface{} {
23 return &bytes.Buffer{}
24 },
25 }
26
27 func getBuffer() *bytes.Buffer {
28 return bufferPool.Get().(*bytes.Buffer)
29 }
30
31 func poolBuffer(buf *bytes.Buffer) {
32 buf.Reset()
33 bufferPool.Put(buf)
34 }
35
36
37 func writeQuotedString(w io.Writer, s string) (int, error) {
38 buf := getBuffer()
39 buf.WriteByte('"')
40 start := 0
41 for i := 0; i < len(s); {
42 if b := s[i]; b < utf8.RuneSelf {
43 if 0x20 <= b && b != '\\' && b != '"' {
44 i++
45 continue
46 }
47 if start < i {
48 buf.WriteString(s[start:i])
49 }
50 switch b {
51 case '\\', '"':
52 buf.WriteByte('\\')
53 buf.WriteByte(b)
54 case '\n':
55 buf.WriteByte('\\')
56 buf.WriteByte('n')
57 case '\r':
58 buf.WriteByte('\\')
59 buf.WriteByte('r')
60 case '\t':
61 buf.WriteByte('\\')
62 buf.WriteByte('t')
63 default:
64
65 buf.WriteString(`\u00`)
66 buf.WriteByte(hex[b>>4])
67 buf.WriteByte(hex[b&0xF])
68 }
69 i++
70 start = i
71 continue
72 }
73 c, size := utf8.DecodeRuneInString(s[i:])
74 if c == utf8.RuneError {
75 if start < i {
76 buf.WriteString(s[start:i])
77 }
78 buf.WriteString(`\ufffd`)
79 i += size
80 start = i
81 continue
82 }
83 i += size
84 }
85 if start < len(s) {
86 buf.WriteString(s[start:])
87 }
88 buf.WriteByte('"')
89 n, err := w.Write(buf.Bytes())
90 poolBuffer(buf)
91 return n, err
92 }
93
94
95 func writeQuotedBytes(w io.Writer, s []byte) (int, error) {
96 buf := getBuffer()
97 buf.WriteByte('"')
98 start := 0
99 for i := 0; i < len(s); {
100 if b := s[i]; b < utf8.RuneSelf {
101 if 0x20 <= b && b != '\\' && b != '"' {
102 i++
103 continue
104 }
105 if start < i {
106 buf.Write(s[start:i])
107 }
108 switch b {
109 case '\\', '"':
110 buf.WriteByte('\\')
111 buf.WriteByte(b)
112 case '\n':
113 buf.WriteByte('\\')
114 buf.WriteByte('n')
115 case '\r':
116 buf.WriteByte('\\')
117 buf.WriteByte('r')
118 case '\t':
119 buf.WriteByte('\\')
120 buf.WriteByte('t')
121 default:
122
123 buf.WriteString(`\u00`)
124 buf.WriteByte(hex[b>>4])
125 buf.WriteByte(hex[b&0xF])
126 }
127 i++
128 start = i
129 continue
130 }
131 c, size := utf8.DecodeRune(s[i:])
132 if c == utf8.RuneError {
133 if start < i {
134 buf.Write(s[start:i])
135 }
136 buf.WriteString(`\ufffd`)
137 i += size
138 start = i
139 continue
140 }
141 i += size
142 }
143 if start < len(s) {
144 buf.Write(s[start:])
145 }
146 buf.WriteByte('"')
147 n, err := w.Write(buf.Bytes())
148 poolBuffer(buf)
149 return n, err
150 }
151
152
153
154 func getu4(s []byte) rune {
155 if len(s) < 6 || s[0] != '\\' || s[1] != 'u' {
156 return -1
157 }
158 r, err := strconv.ParseUint(string(s[2:6]), 16, 64)
159 if err != nil {
160 return -1
161 }
162 return rune(r)
163 }
164
165 func unquoteBytes(s []byte) (t []byte, ok bool) {
166 if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
167 return
168 }
169 s = s[1 : len(s)-1]
170
171
172
173
174 r := 0
175 for r < len(s) {
176 c := s[r]
177 if c == '\\' || c == '"' || c < ' ' {
178 break
179 }
180 if c < utf8.RuneSelf {
181 r++
182 continue
183 }
184 rr, size := utf8.DecodeRune(s[r:])
185 if rr == utf8.RuneError {
186 break
187 }
188 r += size
189 }
190 if r == len(s) {
191 return s, true
192 }
193
194 b := make([]byte, len(s)+2*utf8.UTFMax)
195 w := copy(b, s[0:r])
196 for r < len(s) {
197
198
199
200 if w >= len(b)-2*utf8.UTFMax {
201 nb := make([]byte, (len(b)+utf8.UTFMax)*2)
202 copy(nb, b[0:w])
203 b = nb
204 }
205 switch c := s[r]; {
206 case c == '\\':
207 r++
208 if r >= len(s) {
209 return
210 }
211 switch s[r] {
212 default:
213 return
214 case '"', '\\', '/', '\'':
215 b[w] = s[r]
216 r++
217 w++
218 case 'b':
219 b[w] = '\b'
220 r++
221 w++
222 case 'f':
223 b[w] = '\f'
224 r++
225 w++
226 case 'n':
227 b[w] = '\n'
228 r++
229 w++
230 case 'r':
231 b[w] = '\r'
232 r++
233 w++
234 case 't':
235 b[w] = '\t'
236 r++
237 w++
238 case 'u':
239 r--
240 rr := getu4(s[r:])
241 if rr < 0 {
242 return
243 }
244 r += 6
245 if utf16.IsSurrogate(rr) {
246 rr1 := getu4(s[r:])
247 if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar {
248
249 r += 6
250 w += utf8.EncodeRune(b[w:], dec)
251 break
252 }
253
254 rr = unicode.ReplacementChar
255 }
256 w += utf8.EncodeRune(b[w:], rr)
257 }
258
259
260 case c == '"', c < ' ':
261 return
262
263
264 case c < utf8.RuneSelf:
265 b[w] = c
266 r++
267 w++
268
269
270 default:
271 rr, size := utf8.DecodeRune(s[r:])
272 r += size
273 w += utf8.EncodeRune(b[w:], rr)
274 }
275 }
276 return b[0:w], true
277 }
278
View as plain text