blob: 09df8260a531d40500f8da6f74999184b0d94fec [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001package bson
2
3import (
4 "bytes"
5 "encoding/base64"
6 "fmt"
7 "gopkg.in/mgo.v2/internal/json"
8 "strconv"
9 "time"
10)
11
12// UnmarshalJSON unmarshals a JSON value that may hold non-standard
13// syntax as defined in BSON's extended JSON specification.
14func UnmarshalJSON(data []byte, value interface{}) error {
15 d := json.NewDecoder(bytes.NewBuffer(data))
16 d.Extend(&jsonExt)
17 return d.Decode(value)
18}
19
20// MarshalJSON marshals a JSON value that may hold non-standard
21// syntax as defined in BSON's extended JSON specification.
22func MarshalJSON(value interface{}) ([]byte, error) {
23 var buf bytes.Buffer
24 e := json.NewEncoder(&buf)
25 e.Extend(&jsonExt)
26 err := e.Encode(value)
27 if err != nil {
28 return nil, err
29 }
30 return buf.Bytes(), nil
31}
32
33// jdec is used internally by the JSON decoding functions
34// so they may unmarshal functions without getting into endless
35// recursion due to keyed objects.
36func jdec(data []byte, value interface{}) error {
37 d := json.NewDecoder(bytes.NewBuffer(data))
38 d.Extend(&funcExt)
39 return d.Decode(value)
40}
41
42var jsonExt json.Extension
43var funcExt json.Extension
44
45// TODO
46// - Shell regular expressions ("/regexp/opts")
47
48func init() {
49 jsonExt.DecodeUnquotedKeys(true)
50 jsonExt.DecodeTrailingCommas(true)
51
52 funcExt.DecodeFunc("BinData", "$binaryFunc", "$type", "$binary")
53 jsonExt.DecodeKeyed("$binary", jdecBinary)
54 jsonExt.DecodeKeyed("$binaryFunc", jdecBinary)
55 jsonExt.EncodeType([]byte(nil), jencBinarySlice)
56 jsonExt.EncodeType(Binary{}, jencBinaryType)
57
58 funcExt.DecodeFunc("ISODate", "$dateFunc", "S")
59 funcExt.DecodeFunc("new Date", "$dateFunc", "S")
60 jsonExt.DecodeKeyed("$date", jdecDate)
61 jsonExt.DecodeKeyed("$dateFunc", jdecDate)
62 jsonExt.EncodeType(time.Time{}, jencDate)
63
64 funcExt.DecodeFunc("Timestamp", "$timestamp", "t", "i")
65 jsonExt.DecodeKeyed("$timestamp", jdecTimestamp)
66 jsonExt.EncodeType(MongoTimestamp(0), jencTimestamp)
67
68 funcExt.DecodeConst("undefined", Undefined)
69
70 jsonExt.DecodeKeyed("$regex", jdecRegEx)
71 jsonExt.EncodeType(RegEx{}, jencRegEx)
72
73 funcExt.DecodeFunc("ObjectId", "$oidFunc", "Id")
74 jsonExt.DecodeKeyed("$oid", jdecObjectId)
75 jsonExt.DecodeKeyed("$oidFunc", jdecObjectId)
76 jsonExt.EncodeType(ObjectId(""), jencObjectId)
77
78 funcExt.DecodeFunc("DBRef", "$dbrefFunc", "$ref", "$id")
79 jsonExt.DecodeKeyed("$dbrefFunc", jdecDBRef)
80
81 funcExt.DecodeFunc("NumberLong", "$numberLongFunc", "N")
82 jsonExt.DecodeKeyed("$numberLong", jdecNumberLong)
83 jsonExt.DecodeKeyed("$numberLongFunc", jdecNumberLong)
84 jsonExt.EncodeType(int64(0), jencNumberLong)
85 jsonExt.EncodeType(int(0), jencInt)
86
87 funcExt.DecodeConst("MinKey", MinKey)
88 funcExt.DecodeConst("MaxKey", MaxKey)
89 jsonExt.DecodeKeyed("$minKey", jdecMinKey)
90 jsonExt.DecodeKeyed("$maxKey", jdecMaxKey)
91 jsonExt.EncodeType(orderKey(0), jencMinMaxKey)
92
93 jsonExt.DecodeKeyed("$undefined", jdecUndefined)
94 jsonExt.EncodeType(Undefined, jencUndefined)
95
96 jsonExt.Extend(&funcExt)
97}
98
99func fbytes(format string, args ...interface{}) []byte {
100 var buf bytes.Buffer
101 fmt.Fprintf(&buf, format, args...)
102 return buf.Bytes()
103}
104
105func jdecBinary(data []byte) (interface{}, error) {
106 var v struct {
107 Binary []byte `json:"$binary"`
108 Type string `json:"$type"`
109 Func struct {
110 Binary []byte `json:"$binary"`
111 Type int64 `json:"$type"`
112 } `json:"$binaryFunc"`
113 }
114 err := jdec(data, &v)
115 if err != nil {
116 return nil, err
117 }
118
119 var binData []byte
120 var binKind int64
121 if v.Type == "" && v.Binary == nil {
122 binData = v.Func.Binary
123 binKind = v.Func.Type
124 } else if v.Type == "" {
125 return v.Binary, nil
126 } else {
127 binData = v.Binary
128 binKind, err = strconv.ParseInt(v.Type, 0, 64)
129 if err != nil {
130 binKind = -1
131 }
132 }
133
134 if binKind == 0 {
135 return binData, nil
136 }
137 if binKind < 0 || binKind > 255 {
138 return nil, fmt.Errorf("invalid type in binary object: %s", data)
139 }
140
141 return Binary{Kind: byte(binKind), Data: binData}, nil
142}
143
144func jencBinarySlice(v interface{}) ([]byte, error) {
145 in := v.([]byte)
146 out := make([]byte, base64.StdEncoding.EncodedLen(len(in)))
147 base64.StdEncoding.Encode(out, in)
148 return fbytes(`{"$binary":"%s","$type":"0x0"}`, out), nil
149}
150
151func jencBinaryType(v interface{}) ([]byte, error) {
152 in := v.(Binary)
153 out := make([]byte, base64.StdEncoding.EncodedLen(len(in.Data)))
154 base64.StdEncoding.Encode(out, in.Data)
155 return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil
156}
157
158const jdateFormat = "2006-01-02T15:04:05.999Z"
159
160func jdecDate(data []byte) (interface{}, error) {
161 var v struct {
162 S string `json:"$date"`
163 Func struct {
164 S string
165 } `json:"$dateFunc"`
166 }
167 _ = jdec(data, &v)
168 if v.S == "" {
169 v.S = v.Func.S
170 }
171 if v.S != "" {
172 for _, format := range []string{jdateFormat, "2006-01-02"} {
173 t, err := time.Parse(format, v.S)
174 if err == nil {
175 return t, nil
176 }
177 }
178 return nil, fmt.Errorf("cannot parse date: %q", v.S)
179 }
180
181 var vn struct {
182 Date struct {
183 N int64 `json:"$numberLong,string"`
184 } `json:"$date"`
185 Func struct {
186 S int64
187 } `json:"$dateFunc"`
188 }
189 err := jdec(data, &vn)
190 if err != nil {
191 return nil, fmt.Errorf("cannot parse date: %q", data)
192 }
193 n := vn.Date.N
194 if n == 0 {
195 n = vn.Func.S
196 }
197 return time.Unix(n/1000, n%1000*1e6).UTC(), nil
198}
199
200func jencDate(v interface{}) ([]byte, error) {
201 t := v.(time.Time)
202 return fbytes(`{"$date":%q}`, t.Format(jdateFormat)), nil
203}
204
205func jdecTimestamp(data []byte) (interface{}, error) {
206 var v struct {
207 Func struct {
208 T int32 `json:"t"`
209 I int32 `json:"i"`
210 } `json:"$timestamp"`
211 }
212 err := jdec(data, &v)
213 if err != nil {
214 return nil, err
215 }
216 return MongoTimestamp(uint64(v.Func.T)<<32 | uint64(uint32(v.Func.I))), nil
217}
218
219func jencTimestamp(v interface{}) ([]byte, error) {
220 ts := uint64(v.(MongoTimestamp))
221 return fbytes(`{"$timestamp":{"t":%d,"i":%d}}`, ts>>32, uint32(ts)), nil
222}
223
224func jdecRegEx(data []byte) (interface{}, error) {
225 var v struct {
226 Regex string `json:"$regex"`
227 Options string `json:"$options"`
228 }
229 err := jdec(data, &v)
230 if err != nil {
231 return nil, err
232 }
233 return RegEx{v.Regex, v.Options}, nil
234}
235
236func jencRegEx(v interface{}) ([]byte, error) {
237 re := v.(RegEx)
238 type regex struct {
239 Regex string `json:"$regex"`
240 Options string `json:"$options"`
241 }
242 return json.Marshal(regex{re.Pattern, re.Options})
243}
244
245func jdecObjectId(data []byte) (interface{}, error) {
246 var v struct {
247 Id string `json:"$oid"`
248 Func struct {
249 Id string
250 } `json:"$oidFunc"`
251 }
252 err := jdec(data, &v)
253 if err != nil {
254 return nil, err
255 }
256 if v.Id == "" {
257 v.Id = v.Func.Id
258 }
259 return ObjectIdHex(v.Id), nil
260}
261
262func jencObjectId(v interface{}) ([]byte, error) {
263 return fbytes(`{"$oid":"%s"}`, v.(ObjectId).Hex()), nil
264}
265
266func jdecDBRef(data []byte) (interface{}, error) {
267 // TODO Support unmarshaling $ref and $id into the input value.
268 var v struct {
269 Obj map[string]interface{} `json:"$dbrefFunc"`
270 }
271 // TODO Fix this. Must not be required.
272 v.Obj = make(map[string]interface{})
273 err := jdec(data, &v)
274 if err != nil {
275 return nil, err
276 }
277 return v.Obj, nil
278}
279
280func jdecNumberLong(data []byte) (interface{}, error) {
281 var v struct {
282 N int64 `json:"$numberLong,string"`
283 Func struct {
284 N int64 `json:",string"`
285 } `json:"$numberLongFunc"`
286 }
287 var vn struct {
288 N int64 `json:"$numberLong"`
289 Func struct {
290 N int64
291 } `json:"$numberLongFunc"`
292 }
293 err := jdec(data, &v)
294 if err != nil {
295 err = jdec(data, &vn)
296 v.N = vn.N
297 v.Func.N = vn.Func.N
298 }
299 if err != nil {
300 return nil, err
301 }
302 if v.N != 0 {
303 return v.N, nil
304 }
305 return v.Func.N, nil
306}
307
308func jencNumberLong(v interface{}) ([]byte, error) {
309 n := v.(int64)
310 f := `{"$numberLong":"%d"}`
311 if n <= 1<<53 {
312 f = `{"$numberLong":%d}`
313 }
314 return fbytes(f, n), nil
315}
316
317func jencInt(v interface{}) ([]byte, error) {
318 n := v.(int)
319 f := `{"$numberLong":"%d"}`
320 if int64(n) <= 1<<53 {
321 f = `%d`
322 }
323 return fbytes(f, n), nil
324}
325
326func jdecMinKey(data []byte) (interface{}, error) {
327 var v struct {
328 N int64 `json:"$minKey"`
329 }
330 err := jdec(data, &v)
331 if err != nil {
332 return nil, err
333 }
334 if v.N != 1 {
335 return nil, fmt.Errorf("invalid $minKey object: %s", data)
336 }
337 return MinKey, nil
338}
339
340func jdecMaxKey(data []byte) (interface{}, error) {
341 var v struct {
342 N int64 `json:"$maxKey"`
343 }
344 err := jdec(data, &v)
345 if err != nil {
346 return nil, err
347 }
348 if v.N != 1 {
349 return nil, fmt.Errorf("invalid $maxKey object: %s", data)
350 }
351 return MaxKey, nil
352}
353
354func jencMinMaxKey(v interface{}) ([]byte, error) {
355 switch v.(orderKey) {
356 case MinKey:
357 return []byte(`{"$minKey":1}`), nil
358 case MaxKey:
359 return []byte(`{"$maxKey":1}`), nil
360 }
361 panic(fmt.Sprintf("invalid $minKey/$maxKey value: %d", v))
362}
363
364func jdecUndefined(data []byte) (interface{}, error) {
365 var v struct {
366 B bool `json:"$undefined"`
367 }
368 err := jdec(data, &v)
369 if err != nil {
370 return nil, err
371 }
372 if !v.B {
373 return nil, fmt.Errorf("invalid $undefined object: %s", data)
374 }
375 return Undefined, nil
376}
377
378func jencUndefined(v interface{}) ([]byte, error) {
379 return []byte(`{"$undefined":true}`), nil
380}