1
2
3
4
5
6
7
8
9
10 package json
11
12 import (
13 "bytes"
14 "encoding/base64"
15 "os"
16 "reflect"
17 "runtime"
18 "sort"
19 "strconv"
20 "unicode"
21 "utf8"
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 func Marshal(v interface{}) ([]byte, os.Error) {
92 e := &encodeState{}
93 err := e.marshal(v)
94 if err != nil {
95 return nil, err
96 }
97 return e.Bytes(), nil
98 }
99
100
101 func MarshalIndent(v interface{}, prefix, indent string) ([]byte, os.Error) {
102 b, err := Marshal(v)
103 if err != nil {
104 return nil, err
105 }
106 var buf bytes.Buffer
107 err = Indent(&buf, b, prefix, indent)
108 if err != nil {
109 return nil, err
110 }
111 return buf.Bytes(), nil
112 }
113
114
115 func MarshalForHTML(v interface{}) ([]byte, os.Error) {
116 b, err := Marshal(v)
117 if err != nil {
118 return nil, err
119 }
120 var buf bytes.Buffer
121 HTMLEscape(&buf, b)
122 return buf.Bytes(), nil
123 }
124
125
126
127
128
129
130
131 func HTMLEscape(dst *bytes.Buffer, src []byte) {
132
133
134 start := 0
135 for i, c := range src {
136 if c == '<' || c == '>' || c == '&' {
137 if start < i {
138 dst.Write(src[start:i])
139 }
140 dst.WriteString(`\u00`)
141 dst.WriteByte(hex[c>>4])
142 dst.WriteByte(hex[c&0xF])
143 start = i + 1
144 }
145 }
146 if start < len(src) {
147 dst.Write(src[start:])
148 }
149 }
150
151
152
153 type Marshaler interface {
154 MarshalJSON() ([]byte, os.Error)
155 }
156
157 type UnsupportedTypeError struct {
158 Type reflect.Type
159 }
160
161 func (e *UnsupportedTypeError) String() string {
162 return "json: unsupported type: " + e.Type.String()
163 }
164
165 type InvalidUTF8Error struct {
166 S string
167 }
168
169 func (e *InvalidUTF8Error) String() string {
170 return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
171 }
172
173 type MarshalerError struct {
174 Type reflect.Type
175 Error os.Error
176 }
177
178 func (e *MarshalerError) String() string {
179 return "json: error calling MarshalJSON for type " + e.Type.String() + ": " + e.Error.String()
180 }
181
182 type interfaceOrPtrValue interface {
183 IsNil() bool
184 Elem() reflect.Value
185 }
186
187 var hex = "0123456789abcdef"
188
189
190 type encodeState struct {
191 bytes.Buffer
192 }
193
194 func (e *encodeState) marshal(v interface{}) (err os.Error) {
195 defer func() {
196 if r := recover(); r != nil {
197 if _, ok := r.(runtime.Error); ok {
198 panic(r)
199 }
200 err = r.(os.Error)
201 }
202 }()
203 e.reflectValue(reflect.ValueOf(v))
204 return nil
205 }
206
207 func (e *encodeState) error(err os.Error) {
208 panic(err)
209 }
210
211 var byteSliceType = reflect.TypeOf([]byte(nil))
212
213 func isEmptyValue(v reflect.Value) bool {
214 switch v.Kind() {
215 case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
216 return v.Len() == 0
217 case reflect.Bool:
218 return !v.Bool()
219 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
220 return v.Int() == 0
221 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
222 return v.Uint() == 0
223 case reflect.Float32, reflect.Float64:
224 return v.Float() == 0
225 case reflect.Interface, reflect.Ptr:
226 return v.IsNil()
227 }
228 return false
229 }
230
231 func (e *encodeState) reflectValue(v reflect.Value) {
232 e.reflectValueQuoted(v, false)
233 }
234
235
236
237 func (e *encodeState) reflectValueQuoted(v reflect.Value, quoted bool) {
238 if !v.IsValid() {
239 e.WriteString("null")
240 return
241 }
242
243 if j, ok := v.Interface().(Marshaler); ok {
244 b, err := j.MarshalJSON()
245 if err == nil {
246
247 err = Compact(&e.Buffer, b)
248 }
249 if err != nil {
250 e.error(&MarshalerError{v.Type(), err})
251 }
252 return
253 }
254
255 writeString := (*encodeState).WriteString
256 if quoted {
257 writeString = (*encodeState).string
258 }
259
260 switch v.Kind() {
261 case reflect.Bool:
262 x := v.Bool()
263 if x {
264 writeString(e, "true")
265 } else {
266 writeString(e, "false")
267 }
268
269 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
270 writeString(e, strconv.Itoa64(v.Int()))
271
272 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
273 writeString(e, strconv.Uitoa64(v.Uint()))
274
275 case reflect.Float32, reflect.Float64:
276 writeString(e, strconv.FtoaN(v.Float(), 'g', -1, v.Type().Bits()))
277
278 case reflect.String:
279 if quoted {
280 sb, err := Marshal(v.String())
281 if err != nil {
282 e.error(err)
283 }
284 e.string(string(sb))
285 } else {
286 e.string(v.String())
287 }
288
289 case reflect.Struct:
290 e.WriteByte('{')
291 t := v.Type()
292 n := v.NumField()
293 first := true
294 for i := 0; i < n; i++ {
295 f := t.Field(i)
296 if f.PkgPath != "" {
297 continue
298 }
299 tag, omitEmpty, quoted := f.Name, false, false
300 if tv := f.Tag.Get("json"); tv != "" {
301 name, opts := parseTag(tv)
302 if isValidTag(name) {
303 tag = name
304 }
305 omitEmpty = opts.Contains("omitempty")
306 quoted = opts.Contains("string")
307 }
308 fieldValue := v.Field(i)
309 if omitEmpty && isEmptyValue(fieldValue) {
310 continue
311 }
312 if first {
313 first = false
314 } else {
315 e.WriteByte(',')
316 }
317 e.string(tag)
318 e.WriteByte(':')
319 e.reflectValueQuoted(fieldValue, quoted)
320 }
321 e.WriteByte('}')
322
323 case reflect.Map:
324 if v.Type().Key().Kind() != reflect.String {
325 e.error(&UnsupportedTypeError{v.Type()})
326 }
327 if v.IsNil() {
328 e.WriteString("null")
329 break
330 }
331 e.WriteByte('{')
332 var sv stringValues = v.MapKeys()
333 sort.Sort(sv)
334 for i, k := range sv {
335 if i > 0 {
336 e.WriteByte(',')
337 }
338 e.string(k.String())
339 e.WriteByte(':')
340 e.reflectValue(v.MapIndex(k))
341 }
342 e.WriteByte('}')
343
344 case reflect.Array, reflect.Slice:
345 if v.Type() == byteSliceType {
346 e.WriteByte('"')
347 s := v.Interface().([]byte)
348 if len(s) < 1024 {
349
350 dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
351 base64.StdEncoding.Encode(dst, s)
352 e.Write(dst)
353 } else {
354
355
356 enc := base64.NewEncoder(base64.StdEncoding, e)
357 enc.Write(s)
358 enc.Close()
359 }
360 e.WriteByte('"')
361 break
362 }
363 e.WriteByte('[')
364 n := v.Len()
365 for i := 0; i < n; i++ {
366 if i > 0 {
367 e.WriteByte(',')
368 }
369 e.reflectValue(v.Index(i))
370 }
371 e.WriteByte(']')
372
373 case reflect.Interface, reflect.Ptr:
374 if v.IsNil() {
375 e.WriteString("null")
376 return
377 }
378 e.reflectValue(v.Elem())
379
380 default:
381 e.error(&UnsupportedTypeError{v.Type()})
382 }
383 return
384 }
385
386 func isValidTag(s string) bool {
387 if s == "" {
388 return false
389 }
390 for _, c := range s {
391 if c != '$' && c != '-' && c != '_' && !unicode.IsLetter(c) && !unicode.IsDigit(c) {
392 return false
393 }
394 }
395 return true
396 }
397
398
399
400 type stringValues []reflect.Value
401
402 func (sv stringValues) Len() int { return len(sv) }
403 func (sv stringValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
404 func (sv stringValues) Less(i, j int) bool { return sv.get(i) < sv.get(j) }
405 func (sv stringValues) get(i int) string { return sv[i].String() }
406
407 func (e *encodeState) string(s string) (int, os.Error) {
408 len0 := e.Len()
409 e.WriteByte('"')
410 start := 0
411 for i := 0; i < len(s); {
412 if b := s[i]; b < utf8.RuneSelf {
413 if 0x20 <= b && b != '\\' && b != '"' && b != '<' && b != '>' {
414 i++
415 continue
416 }
417 if start < i {
418 e.WriteString(s[start:i])
419 }
420 switch b {
421 case '\\', '"':
422 e.WriteByte('\\')
423 e.WriteByte(b)
424 case '\n':
425 e.WriteByte('\\')
426 e.WriteByte('n')
427 case '\r':
428 e.WriteByte('\\')
429 e.WriteByte('r')
430 default:
431
432
433
434
435 e.WriteString(`\u00`)
436 e.WriteByte(hex[b>>4])
437 e.WriteByte(hex[b&0xF])
438 }
439 i++
440 start = i
441 continue
442 }
443 c, size := utf8.DecodeRuneInString(s[i:])
444 if c == utf8.RuneError && size == 1 {
445 e.error(&InvalidUTF8Error{s})
446 }
447 i += size
448 }
449 if start < len(s) {
450 e.WriteString(s[start:])
451 }
452 e.WriteByte('"')
453 return e.Len() - len0, nil
454 }