LEFT | RIGHT |
1 // Copyright 2010 The Go Authors. All rights reserved. | 1 // Copyright 2010 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package json | 5 package json |
6 | 6 |
7 import ( | 7 import ( |
8 "os" | 8 "os" |
9 "bytes" | 9 "bytes" |
10 "reflect" | 10 "reflect" |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 return nil, err | 69 return nil, err |
70 } | 70 } |
71 var buf bytes.Buffer | 71 var buf bytes.Buffer |
72 err = Indent(&buf, b, prefix, indent) | 72 err = Indent(&buf, b, prefix, indent) |
73 if err != nil { | 73 if err != nil { |
74 return nil, err | 74 return nil, err |
75 } | 75 } |
76 return buf.Bytes(), nil | 76 return buf.Bytes(), nil |
77 } | 77 } |
78 | 78 |
79 // HTMLEscape re-encodes <, >, and & characters in JSON data so | 79 // MarshalForHTML is like Marshal but applies HTMLEscape to the output. |
80 // they may be safely embedded in HTML. For historical reasons, | 80 func MarshalForHTML(v interface{}) ([]byte, os.Error) { |
81 // browsers don't honor standard HTML escaping within <script> | 81 » b, err := Marshal(v) |
82 // tags, so an alternative JSON encoding must be used. | 82 » if err != nil { |
83 func HTMLEscape(json []byte) []byte { | 83 » » return nil, err |
84 » var b bytes.Buffer | 84 » } |
85 » for _, c := range json { | 85 » var buf bytes.Buffer |
86 » » switch c { | 86 » HTMLEscape(&buf, b) |
87 » » case '<', '>', '&': | 87 » return buf.Bytes(), nil |
88 » » » b.WriteString(`\u00`) | 88 } |
89 » » » b.WriteByte(hex[c>>4]) | 89 |
90 » » » b.WriteByte(hex[c&0xF]) | 90 // HTMLEscape appends to dst the JSON-encoded src with <, >, and & |
91 » » default: | 91 // characters inside string literals changed to \u003c, \u003e, \u0026 |
92 » » » b.WriteByte(c) | 92 // so that the JSON will be safe to embed inside HTML <script> tags. |
93 » » } | 93 // For historical reasons, web browsers don't honor standard HTML |
94 » } | 94 // escaping within <script> tags, so an alternative JSON encoding must |
95 » return b.Bytes() | 95 // be used. |
| 96 func HTMLEscape(dst *bytes.Buffer, src []byte) { |
| 97 » // < > & can only appear in string literals, |
| 98 » // so just scan the string one byte at a time. |
| 99 » start := 0 |
| 100 » for i, c := range src { |
| 101 » » if c == '<' || c == '>' || c == '&' { |
| 102 » » » if start < i { |
| 103 » » » » dst.Write(src[start:i]) |
| 104 » » » } |
| 105 » » » dst.WriteString(`\u00`) |
| 106 » » » dst.WriteByte(hex[c>>4]) |
| 107 » » » dst.WriteByte(hex[c&0xF]) |
| 108 » » » start = i + 1 |
| 109 » » } |
| 110 » } |
| 111 » if start < len(src) { |
| 112 » » dst.Write(src[start:]) |
| 113 » } |
96 } | 114 } |
97 | 115 |
98 // Marshaler is the interface implemented by objects that | 116 // Marshaler is the interface implemented by objects that |
99 // can marshal themselves into valid JSON. | 117 // can marshal themselves into valid JSON. |
100 type Marshaler interface { | 118 type Marshaler interface { |
101 MarshalJSON() ([]byte, os.Error) | 119 MarshalJSON() ([]byte, os.Error) |
102 } | 120 } |
103 | 121 |
104 type UnsupportedTypeError struct { | 122 type UnsupportedTypeError struct { |
105 Type reflect.Type | 123 Type reflect.Type |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 switch v := v.(type) { | 186 switch v := v.(type) { |
169 case *reflect.BoolValue: | 187 case *reflect.BoolValue: |
170 x := v.Get() | 188 x := v.Get() |
171 if x { | 189 if x { |
172 e.WriteString("true") | 190 e.WriteString("true") |
173 } else { | 191 } else { |
174 e.WriteString("false") | 192 e.WriteString("false") |
175 } | 193 } |
176 | 194 |
177 case *reflect.IntValue: | 195 case *reflect.IntValue: |
178 e.WriteString(strconv.Itoa(v.Get())) | |
179 case *reflect.Int8Value: | |
180 e.WriteString(strconv.Itoa(int(v.Get()))) | |
181 case *reflect.Int16Value: | |
182 e.WriteString(strconv.Itoa(int(v.Get()))) | |
183 case *reflect.Int32Value: | |
184 e.WriteString(strconv.Itoa(int(v.Get()))) | |
185 case *reflect.Int64Value: | |
186 e.WriteString(strconv.Itoa64(v.Get())) | 196 e.WriteString(strconv.Itoa64(v.Get())) |
187 | 197 |
188 case *reflect.UintValue: | 198 case *reflect.UintValue: |
189 e.WriteString(strconv.Uitoa(v.Get())) | |
190 case *reflect.Uint8Value: | |
191 e.WriteString(strconv.Uitoa(uint(v.Get()))) | |
192 case *reflect.Uint16Value: | |
193 e.WriteString(strconv.Uitoa(uint(v.Get()))) | |
194 case *reflect.Uint32Value: | |
195 e.WriteString(strconv.Uitoa(uint(v.Get()))) | |
196 case *reflect.Uint64Value: | |
197 e.WriteString(strconv.Uitoa64(v.Get())) | 199 e.WriteString(strconv.Uitoa64(v.Get())) |
198 case *reflect.UintptrValue: | |
199 e.WriteString(strconv.Uitoa64(uint64(v.Get()))) | |
200 | 200 |
201 case *reflect.FloatValue: | 201 case *reflect.FloatValue: |
202 » » e.WriteString(strconv.Ftoa(v.Get(), 'g', -1)) | 202 » » e.WriteString(strconv.FtoaN(v.Get(), 'g', -1, v.Type().Bits())) |
203 » case *reflect.Float32Value: | |
204 » » e.WriteString(strconv.Ftoa32(v.Get(), 'g', -1)) | |
205 » case *reflect.Float64Value: | |
206 » » e.WriteString(strconv.Ftoa64(v.Get(), 'g', -1)) | |
207 | 203 |
208 case *reflect.StringValue: | 204 case *reflect.StringValue: |
209 e.string(v.Get()) | 205 e.string(v.Get()) |
210 | 206 |
211 case *reflect.StructValue: | 207 case *reflect.StructValue: |
212 e.WriteByte('{') | 208 e.WriteByte('{') |
213 t := v.Type().(*reflect.StructType) | 209 t := v.Type().(*reflect.StructType) |
214 n := v.NumField() | 210 n := v.NumField() |
215 for i := 0; i < n; i++ { | 211 for i := 0; i < n; i++ { |
216 if i > 0 { | 212 if i > 0 { |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
291 e.WriteByte(hex[c&0xF]) | 287 e.WriteByte(hex[c&0xF]) |
292 case c == '\\' || c == '"': | 288 case c == '\\' || c == '"': |
293 e.WriteByte('\\') | 289 e.WriteByte('\\') |
294 fallthrough | 290 fallthrough |
295 default: | 291 default: |
296 e.WriteRune(c) | 292 e.WriteRune(c) |
297 } | 293 } |
298 } | 294 } |
299 e.WriteByte('"') | 295 e.WriteByte('"') |
300 } | 296 } |
LEFT | RIGHT |