1
2 package jwriter
3
4 import (
5 "io"
6 "strconv"
7 "unicode/utf8"
8
9 "github.com/mailru/easyjson/buffer"
10 )
11
12
13
14 type Flags int
15
16 const (
17 NilMapAsEmpty Flags = 1 << iota
18 NilSliceAsEmpty
19 )
20
21
22 type Writer struct {
23 Flags Flags
24
25 Error error
26 Buffer buffer.Buffer
27 NoEscapeHTML bool
28 }
29
30
31 func (w *Writer) Size() int {
32 return w.Buffer.Size()
33 }
34
35
36 func (w *Writer) DumpTo(out io.Writer) (written int, err error) {
37 return w.Buffer.DumpTo(out)
38 }
39
40
41
42 func (w *Writer) BuildBytes(reuse ...[]byte) ([]byte, error) {
43 if w.Error != nil {
44 return nil, w.Error
45 }
46
47 return w.Buffer.BuildBytes(reuse...), nil
48 }
49
50
51
52 func (w *Writer) ReadCloser() (io.ReadCloser, error) {
53 if w.Error != nil {
54 return nil, w.Error
55 }
56
57 return w.Buffer.ReadCloser(), nil
58 }
59
60
61 func (w *Writer) RawByte(c byte) {
62 w.Buffer.AppendByte(c)
63 }
64
65
66 func (w *Writer) RawString(s string) {
67 w.Buffer.AppendString(s)
68 }
69
70
71
72 func (w *Writer) Raw(data []byte, err error) {
73 switch {
74 case w.Error != nil:
75 return
76 case err != nil:
77 w.Error = err
78 case len(data) > 0:
79 w.Buffer.AppendBytes(data)
80 default:
81 w.RawString("null")
82 }
83 }
84
85
86
87 func (w *Writer) RawText(data []byte, err error) {
88 switch {
89 case w.Error != nil:
90 return
91 case err != nil:
92 w.Error = err
93 case len(data) > 0:
94 w.String(string(data))
95 default:
96 w.RawString("null")
97 }
98 }
99
100
101 func (w *Writer) Base64Bytes(data []byte) {
102 if data == nil {
103 w.Buffer.AppendString("null")
104 return
105 }
106 w.Buffer.AppendByte('"')
107 w.base64(data)
108 w.Buffer.AppendByte('"')
109 }
110
111 func (w *Writer) Uint8(n uint8) {
112 w.Buffer.EnsureSpace(3)
113 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
114 }
115
116 func (w *Writer) Uint16(n uint16) {
117 w.Buffer.EnsureSpace(5)
118 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
119 }
120
121 func (w *Writer) Uint32(n uint32) {
122 w.Buffer.EnsureSpace(10)
123 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
124 }
125
126 func (w *Writer) Uint(n uint) {
127 w.Buffer.EnsureSpace(20)
128 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
129 }
130
131 func (w *Writer) Uint64(n uint64) {
132 w.Buffer.EnsureSpace(20)
133 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
134 }
135
136 func (w *Writer) Int8(n int8) {
137 w.Buffer.EnsureSpace(4)
138 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
139 }
140
141 func (w *Writer) Int16(n int16) {
142 w.Buffer.EnsureSpace(6)
143 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
144 }
145
146 func (w *Writer) Int32(n int32) {
147 w.Buffer.EnsureSpace(11)
148 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
149 }
150
151 func (w *Writer) Int(n int) {
152 w.Buffer.EnsureSpace(21)
153 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
154 }
155
156 func (w *Writer) Int64(n int64) {
157 w.Buffer.EnsureSpace(21)
158 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
159 }
160
161 func (w *Writer) Uint8Str(n uint8) {
162 w.Buffer.EnsureSpace(3)
163 w.Buffer.Buf = append(w.Buffer.Buf, '"')
164 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
165 w.Buffer.Buf = append(w.Buffer.Buf, '"')
166 }
167
168 func (w *Writer) Uint16Str(n uint16) {
169 w.Buffer.EnsureSpace(5)
170 w.Buffer.Buf = append(w.Buffer.Buf, '"')
171 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
172 w.Buffer.Buf = append(w.Buffer.Buf, '"')
173 }
174
175 func (w *Writer) Uint32Str(n uint32) {
176 w.Buffer.EnsureSpace(10)
177 w.Buffer.Buf = append(w.Buffer.Buf, '"')
178 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
179 w.Buffer.Buf = append(w.Buffer.Buf, '"')
180 }
181
182 func (w *Writer) UintStr(n uint) {
183 w.Buffer.EnsureSpace(20)
184 w.Buffer.Buf = append(w.Buffer.Buf, '"')
185 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
186 w.Buffer.Buf = append(w.Buffer.Buf, '"')
187 }
188
189 func (w *Writer) Uint64Str(n uint64) {
190 w.Buffer.EnsureSpace(20)
191 w.Buffer.Buf = append(w.Buffer.Buf, '"')
192 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
193 w.Buffer.Buf = append(w.Buffer.Buf, '"')
194 }
195
196 func (w *Writer) UintptrStr(n uintptr) {
197 w.Buffer.EnsureSpace(20)
198 w.Buffer.Buf = append(w.Buffer.Buf, '"')
199 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
200 w.Buffer.Buf = append(w.Buffer.Buf, '"')
201 }
202
203 func (w *Writer) Int8Str(n int8) {
204 w.Buffer.EnsureSpace(4)
205 w.Buffer.Buf = append(w.Buffer.Buf, '"')
206 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
207 w.Buffer.Buf = append(w.Buffer.Buf, '"')
208 }
209
210 func (w *Writer) Int16Str(n int16) {
211 w.Buffer.EnsureSpace(6)
212 w.Buffer.Buf = append(w.Buffer.Buf, '"')
213 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
214 w.Buffer.Buf = append(w.Buffer.Buf, '"')
215 }
216
217 func (w *Writer) Int32Str(n int32) {
218 w.Buffer.EnsureSpace(11)
219 w.Buffer.Buf = append(w.Buffer.Buf, '"')
220 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
221 w.Buffer.Buf = append(w.Buffer.Buf, '"')
222 }
223
224 func (w *Writer) IntStr(n int) {
225 w.Buffer.EnsureSpace(21)
226 w.Buffer.Buf = append(w.Buffer.Buf, '"')
227 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
228 w.Buffer.Buf = append(w.Buffer.Buf, '"')
229 }
230
231 func (w *Writer) Int64Str(n int64) {
232 w.Buffer.EnsureSpace(21)
233 w.Buffer.Buf = append(w.Buffer.Buf, '"')
234 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
235 w.Buffer.Buf = append(w.Buffer.Buf, '"')
236 }
237
238 func (w *Writer) Float32(n float32) {
239 w.Buffer.EnsureSpace(20)
240 w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
241 }
242
243 func (w *Writer) Float32Str(n float32) {
244 w.Buffer.EnsureSpace(20)
245 w.Buffer.Buf = append(w.Buffer.Buf, '"')
246 w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
247 w.Buffer.Buf = append(w.Buffer.Buf, '"')
248 }
249
250 func (w *Writer) Float64(n float64) {
251 w.Buffer.EnsureSpace(20)
252 w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, 'g', -1, 64)
253 }
254
255 func (w *Writer) Float64Str(n float64) {
256 w.Buffer.EnsureSpace(20)
257 w.Buffer.Buf = append(w.Buffer.Buf, '"')
258 w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 64)
259 w.Buffer.Buf = append(w.Buffer.Buf, '"')
260 }
261
262 func (w *Writer) Bool(v bool) {
263 w.Buffer.EnsureSpace(5)
264 if v {
265 w.Buffer.Buf = append(w.Buffer.Buf, "true"...)
266 } else {
267 w.Buffer.Buf = append(w.Buffer.Buf, "false"...)
268 }
269 }
270
271 const chars = "0123456789abcdef"
272
273 func getTable(falseValues ...int) [128]bool {
274 table := [128]bool{}
275
276 for i := 0; i < 128; i++ {
277 table[i] = true
278 }
279
280 for _, v := range falseValues {
281 table[v] = false
282 }
283
284 return table
285 }
286
287 var (
288 htmlEscapeTable = getTable(0, 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, '"', '&', '<', '>', '\\')
289 htmlNoEscapeTable = getTable(0, 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, '"', '\\')
290 )
291
292 func (w *Writer) String(s string) {
293 w.Buffer.AppendByte('"')
294
295
296
297
298 p := 0
299
300 escapeTable := &htmlEscapeTable
301 if w.NoEscapeHTML {
302 escapeTable = &htmlNoEscapeTable
303 }
304
305 for i := 0; i < len(s); {
306 c := s[i]
307
308 if c < utf8.RuneSelf {
309 if escapeTable[c] {
310
311 i++
312 continue
313 }
314
315 w.Buffer.AppendString(s[p:i])
316 switch c {
317 case '\t':
318 w.Buffer.AppendString(`\t`)
319 case '\r':
320 w.Buffer.AppendString(`\r`)
321 case '\n':
322 w.Buffer.AppendString(`\n`)
323 case '\\':
324 w.Buffer.AppendString(`\\`)
325 case '"':
326 w.Buffer.AppendString(`\"`)
327 default:
328 w.Buffer.AppendString(`\u00`)
329 w.Buffer.AppendByte(chars[c>>4])
330 w.Buffer.AppendByte(chars[c&0xf])
331 }
332
333 i++
334 p = i
335 continue
336 }
337
338
339 runeValue, runeWidth := utf8.DecodeRuneInString(s[i:])
340 if runeValue == utf8.RuneError && runeWidth == 1 {
341 w.Buffer.AppendString(s[p:i])
342 w.Buffer.AppendString(`\ufffd`)
343 i++
344 p = i
345 continue
346 }
347
348
349 if runeValue == '\u2028' || runeValue == '\u2029' {
350 w.Buffer.AppendString(s[p:i])
351 w.Buffer.AppendString(`\u202`)
352 w.Buffer.AppendByte(chars[runeValue&0xf])
353 i += runeWidth
354 p = i
355 continue
356 }
357 i += runeWidth
358 }
359 w.Buffer.AppendString(s[p:])
360 w.Buffer.AppendByte('"')
361 }
362
363 const encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
364 const padChar = '='
365
366 func (w *Writer) base64(in []byte) {
367
368 if len(in) == 0 {
369 return
370 }
371
372 w.Buffer.EnsureSpace(((len(in)-1)/3 + 1) * 4)
373
374 si := 0
375 n := (len(in) / 3) * 3
376
377 for si < n {
378
379 val := uint(in[si+0])<<16 | uint(in[si+1])<<8 | uint(in[si+2])
380
381 w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F], encode[val>>6&0x3F], encode[val&0x3F])
382
383 si += 3
384 }
385
386 remain := len(in) - si
387 if remain == 0 {
388 return
389 }
390
391
392 val := uint(in[si+0]) << 16
393 if remain == 2 {
394 val |= uint(in[si+1]) << 8
395 }
396
397 w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F])
398
399 switch remain {
400 case 2:
401 w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>6&0x3F], byte(padChar))
402 case 1:
403 w.Buffer.Buf = append(w.Buffer.Buf, byte(padChar), byte(padChar))
404 }
405 }
406
View as plain text