OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / vendor / github.com / go-logfmt / logfmt / jsonstring.go
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 // Taken from Go's encoding/json and modified for use here.
14
15 // Copyright 2010 The Go Authors. All rights reserved.
16 // Use of this source code is governed by a BSD-style
17 // license that can be found in the LICENSE file.
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 // NOTE: keep in sync with writeQuotedBytes below.
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                                 // This encodes bytes < 0x20 except for \n, \r, and \t.
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 // NOTE: keep in sync with writeQuoteString above.
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                                 // This encodes bytes < 0x20 except for \n, \r, and \t.
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 // getu4 decodes \uXXXX from the beginning of s, returning the hex value,
153 // or it returns -1.
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         // Check for unusual characters. If there are none,
172         // then no unquoting is needed, so return a slice of the
173         // original bytes.
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                 // Out of room?  Can only happen if s is full of
198                 // malformed UTF-8 and we're replacing each
199                 // byte with RuneError.
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                                                 // A valid pair; consume.
249                                                 r += 6
250                                                 w += utf8.EncodeRune(b[w:], dec)
251                                                 break
252                                         }
253                                         // Invalid surrogate; fall back to replacement rune.
254                                         rr = unicode.ReplacementChar
255                                 }
256                                 w += utf8.EncodeRune(b[w:], rr)
257                         }
258
259                 // Quote, control characters are invalid.
260                 case c == '"', c < ' ':
261                         return
262
263                 // ASCII
264                 case c < utf8.RuneSelf:
265                         b[w] = c
266                         r++
267                         w++
268
269                 // Coerce to well-formed UTF-8.
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 }