blob: add39e865ddd0fe6470cfaebb20f78b02ef621b1 [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// BSON library for Go
2//
3// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
4//
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are met:
9//
10// 1. Redistributions of source code must retain the above copyright notice, this
11// list of conditions and the following disclaimer.
12// 2. Redistributions in binary form must reproduce the above copyright notice,
13// this list of conditions and the following disclaimer in the documentation
14// and/or other materials provided with the distribution.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26// gobson - BSON library for Go.
27
28package bson
29
30import (
31 "encoding/json"
32 "fmt"
33 "math"
34 "net/url"
35 "reflect"
36 "strconv"
37 "time"
38)
39
40// --------------------------------------------------------------------------
41// Some internal infrastructure.
42
43var (
44 typeBinary = reflect.TypeOf(Binary{})
45 typeObjectId = reflect.TypeOf(ObjectId(""))
46 typeDBPointer = reflect.TypeOf(DBPointer{"", ObjectId("")})
47 typeSymbol = reflect.TypeOf(Symbol(""))
48 typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0))
49 typeOrderKey = reflect.TypeOf(MinKey)
50 typeDocElem = reflect.TypeOf(DocElem{})
51 typeRawDocElem = reflect.TypeOf(RawDocElem{})
52 typeRaw = reflect.TypeOf(Raw{})
53 typeURL = reflect.TypeOf(url.URL{})
54 typeTime = reflect.TypeOf(time.Time{})
55 typeString = reflect.TypeOf("")
56 typeJSONNumber = reflect.TypeOf(json.Number(""))
57)
58
59const itoaCacheSize = 32
60
61var itoaCache []string
62
63func init() {
64 itoaCache = make([]string, itoaCacheSize)
65 for i := 0; i != itoaCacheSize; i++ {
66 itoaCache[i] = strconv.Itoa(i)
67 }
68}
69
70func itoa(i int) string {
71 if i < itoaCacheSize {
72 return itoaCache[i]
73 }
74 return strconv.Itoa(i)
75}
76
77// --------------------------------------------------------------------------
78// Marshaling of the document value itself.
79
80type encoder struct {
81 out []byte
82}
83
84func (e *encoder) addDoc(v reflect.Value) {
85 for {
86 if vi, ok := v.Interface().(Getter); ok {
87 getv, err := vi.GetBSON()
88 if err != nil {
89 panic(err)
90 }
91 v = reflect.ValueOf(getv)
92 continue
93 }
94 if v.Kind() == reflect.Ptr {
95 v = v.Elem()
96 continue
97 }
98 break
99 }
100
101 if v.Type() == typeRaw {
102 raw := v.Interface().(Raw)
103 if raw.Kind != 0x03 && raw.Kind != 0x00 {
104 panic("Attempted to marshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document")
105 }
106 if len(raw.Data) == 0 {
107 panic("Attempted to marshal empty Raw document")
108 }
109 e.addBytes(raw.Data...)
110 return
111 }
112
113 start := e.reserveInt32()
114
115 switch v.Kind() {
116 case reflect.Map:
117 e.addMap(v)
118 case reflect.Struct:
119 e.addStruct(v)
120 case reflect.Array, reflect.Slice:
121 e.addSlice(v)
122 default:
123 panic("Can't marshal " + v.Type().String() + " as a BSON document")
124 }
125
126 e.addBytes(0)
127 e.setInt32(start, int32(len(e.out)-start))
128}
129
130func (e *encoder) addMap(v reflect.Value) {
131 for _, k := range v.MapKeys() {
132 e.addElem(k.String(), v.MapIndex(k), false)
133 }
134}
135
136func (e *encoder) addStruct(v reflect.Value) {
137 sinfo, err := getStructInfo(v.Type())
138 if err != nil {
139 panic(err)
140 }
141 var value reflect.Value
142 if sinfo.InlineMap >= 0 {
143 m := v.Field(sinfo.InlineMap)
144 if m.Len() > 0 {
145 for _, k := range m.MapKeys() {
146 ks := k.String()
147 if _, found := sinfo.FieldsMap[ks]; found {
148 panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks))
149 }
150 e.addElem(ks, m.MapIndex(k), false)
151 }
152 }
153 }
154 for _, info := range sinfo.FieldsList {
155 if info.Inline == nil {
156 value = v.Field(info.Num)
157 } else {
158 value = v.FieldByIndex(info.Inline)
159 }
160 if info.OmitEmpty && isZero(value) {
161 continue
162 }
163 e.addElem(info.Key, value, info.MinSize)
164 }
165}
166
167func isZero(v reflect.Value) bool {
168 switch v.Kind() {
169 case reflect.String:
170 return len(v.String()) == 0
171 case reflect.Ptr, reflect.Interface:
172 return v.IsNil()
173 case reflect.Slice:
174 return v.Len() == 0
175 case reflect.Map:
176 return v.Len() == 0
177 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
178 return v.Int() == 0
179 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
180 return v.Uint() == 0
181 case reflect.Float32, reflect.Float64:
182 return v.Float() == 0
183 case reflect.Bool:
184 return !v.Bool()
185 case reflect.Struct:
186 vt := v.Type()
187 if vt == typeTime {
188 return v.Interface().(time.Time).IsZero()
189 }
190 for i := 0; i < v.NumField(); i++ {
191 if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous {
192 continue // Private field
193 }
194 if !isZero(v.Field(i)) {
195 return false
196 }
197 }
198 return true
199 }
200 return false
201}
202
203func (e *encoder) addSlice(v reflect.Value) {
204 vi := v.Interface()
205 if d, ok := vi.(D); ok {
206 for _, elem := range d {
207 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
208 }
209 return
210 }
211 if d, ok := vi.(RawD); ok {
212 for _, elem := range d {
213 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
214 }
215 return
216 }
217 l := v.Len()
218 et := v.Type().Elem()
219 if et == typeDocElem {
220 for i := 0; i < l; i++ {
221 elem := v.Index(i).Interface().(DocElem)
222 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
223 }
224 return
225 }
226 if et == typeRawDocElem {
227 for i := 0; i < l; i++ {
228 elem := v.Index(i).Interface().(RawDocElem)
229 e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
230 }
231 return
232 }
233 for i := 0; i < l; i++ {
234 e.addElem(itoa(i), v.Index(i), false)
235 }
236}
237
238// --------------------------------------------------------------------------
239// Marshaling of elements in a document.
240
241func (e *encoder) addElemName(kind byte, name string) {
242 e.addBytes(kind)
243 e.addBytes([]byte(name)...)
244 e.addBytes(0)
245}
246
247func (e *encoder) addElem(name string, v reflect.Value, minSize bool) {
248
249 if !v.IsValid() {
250 e.addElemName(0x0A, name)
251 return
252 }
253
254 if getter, ok := v.Interface().(Getter); ok {
255 getv, err := getter.GetBSON()
256 if err != nil {
257 panic(err)
258 }
259 e.addElem(name, reflect.ValueOf(getv), minSize)
260 return
261 }
262
263 switch v.Kind() {
264
265 case reflect.Interface:
266 e.addElem(name, v.Elem(), minSize)
267
268 case reflect.Ptr:
269 e.addElem(name, v.Elem(), minSize)
270
271 case reflect.String:
272 s := v.String()
273 switch v.Type() {
274 case typeObjectId:
275 if len(s) != 12 {
276 panic("ObjectIDs must be exactly 12 bytes long (got " +
277 strconv.Itoa(len(s)) + ")")
278 }
279 e.addElemName(0x07, name)
280 e.addBytes([]byte(s)...)
281 case typeSymbol:
282 e.addElemName(0x0E, name)
283 e.addStr(s)
284 case typeJSONNumber:
285 n := v.Interface().(json.Number)
286 if i, err := n.Int64(); err == nil {
287 e.addElemName(0x12, name)
288 e.addInt64(i)
289 } else if f, err := n.Float64(); err == nil {
290 e.addElemName(0x01, name)
291 e.addFloat64(f)
292 } else {
293 panic("failed to convert json.Number to a number: " + s)
294 }
295 default:
296 e.addElemName(0x02, name)
297 e.addStr(s)
298 }
299
300 case reflect.Float32, reflect.Float64:
301 e.addElemName(0x01, name)
302 e.addFloat64(v.Float())
303
304 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
305 u := v.Uint()
306 if int64(u) < 0 {
307 panic("BSON has no uint64 type, and value is too large to fit correctly in an int64")
308 } else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) {
309 e.addElemName(0x10, name)
310 e.addInt32(int32(u))
311 } else {
312 e.addElemName(0x12, name)
313 e.addInt64(int64(u))
314 }
315
316 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
317 switch v.Type() {
318 case typeMongoTimestamp:
319 e.addElemName(0x11, name)
320 e.addInt64(v.Int())
321
322 case typeOrderKey:
323 if v.Int() == int64(MaxKey) {
324 e.addElemName(0x7F, name)
325 } else {
326 e.addElemName(0xFF, name)
327 }
328
329 default:
330 i := v.Int()
331 if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 {
332 // It fits into an int32, encode as such.
333 e.addElemName(0x10, name)
334 e.addInt32(int32(i))
335 } else {
336 e.addElemName(0x12, name)
337 e.addInt64(i)
338 }
339 }
340
341 case reflect.Bool:
342 e.addElemName(0x08, name)
343 if v.Bool() {
344 e.addBytes(1)
345 } else {
346 e.addBytes(0)
347 }
348
349 case reflect.Map:
350 e.addElemName(0x03, name)
351 e.addDoc(v)
352
353 case reflect.Slice:
354 vt := v.Type()
355 et := vt.Elem()
356 if et.Kind() == reflect.Uint8 {
357 e.addElemName(0x05, name)
358 e.addBinary(0x00, v.Bytes())
359 } else if et == typeDocElem || et == typeRawDocElem {
360 e.addElemName(0x03, name)
361 e.addDoc(v)
362 } else {
363 e.addElemName(0x04, name)
364 e.addDoc(v)
365 }
366
367 case reflect.Array:
368 et := v.Type().Elem()
369 if et.Kind() == reflect.Uint8 {
370 e.addElemName(0x05, name)
371 if v.CanAddr() {
372 e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte))
373 } else {
374 n := v.Len()
375 e.addInt32(int32(n))
376 e.addBytes(0x00)
377 for i := 0; i < n; i++ {
378 el := v.Index(i)
379 e.addBytes(byte(el.Uint()))
380 }
381 }
382 } else {
383 e.addElemName(0x04, name)
384 e.addDoc(v)
385 }
386
387 case reflect.Struct:
388 switch s := v.Interface().(type) {
389
390 case Raw:
391 kind := s.Kind
392 if kind == 0x00 {
393 kind = 0x03
394 }
395 if len(s.Data) == 0 && kind != 0x06 && kind != 0x0A && kind != 0xFF && kind != 0x7F {
396 panic("Attempted to marshal empty Raw document")
397 }
398 e.addElemName(kind, name)
399 e.addBytes(s.Data...)
400
401 case Binary:
402 e.addElemName(0x05, name)
403 e.addBinary(s.Kind, s.Data)
404
405 case Decimal128:
406 e.addElemName(0x13, name)
407 e.addInt64(int64(s.l))
408 e.addInt64(int64(s.h))
409
410 case DBPointer:
411 e.addElemName(0x0C, name)
412 e.addStr(s.Namespace)
413 if len(s.Id) != 12 {
414 panic("ObjectIDs must be exactly 12 bytes long (got " +
415 strconv.Itoa(len(s.Id)) + ")")
416 }
417 e.addBytes([]byte(s.Id)...)
418
419 case RegEx:
420 e.addElemName(0x0B, name)
421 e.addCStr(s.Pattern)
422 e.addCStr(s.Options)
423
424 case JavaScript:
425 if s.Scope == nil {
426 e.addElemName(0x0D, name)
427 e.addStr(s.Code)
428 } else {
429 e.addElemName(0x0F, name)
430 start := e.reserveInt32()
431 e.addStr(s.Code)
432 e.addDoc(reflect.ValueOf(s.Scope))
433 e.setInt32(start, int32(len(e.out)-start))
434 }
435
436 case time.Time:
437 // MongoDB handles timestamps as milliseconds.
438 e.addElemName(0x09, name)
439 e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6))
440
441 case url.URL:
442 e.addElemName(0x02, name)
443 e.addStr(s.String())
444
445 case undefined:
446 e.addElemName(0x06, name)
447
448 default:
449 e.addElemName(0x03, name)
450 e.addDoc(v)
451 }
452
453 default:
454 panic("Can't marshal " + v.Type().String() + " in a BSON document")
455 }
456}
457
458// --------------------------------------------------------------------------
459// Marshaling of base types.
460
461func (e *encoder) addBinary(subtype byte, v []byte) {
462 if subtype == 0x02 {
463 // Wonder how that brilliant idea came to life. Obsolete, luckily.
464 e.addInt32(int32(len(v) + 4))
465 e.addBytes(subtype)
466 e.addInt32(int32(len(v)))
467 } else {
468 e.addInt32(int32(len(v)))
469 e.addBytes(subtype)
470 }
471 e.addBytes(v...)
472}
473
474func (e *encoder) addStr(v string) {
475 e.addInt32(int32(len(v) + 1))
476 e.addCStr(v)
477}
478
479func (e *encoder) addCStr(v string) {
480 e.addBytes([]byte(v)...)
481 e.addBytes(0)
482}
483
484func (e *encoder) reserveInt32() (pos int) {
485 pos = len(e.out)
486 e.addBytes(0, 0, 0, 0)
487 return pos
488}
489
490func (e *encoder) setInt32(pos int, v int32) {
491 e.out[pos+0] = byte(v)
492 e.out[pos+1] = byte(v >> 8)
493 e.out[pos+2] = byte(v >> 16)
494 e.out[pos+3] = byte(v >> 24)
495}
496
497func (e *encoder) addInt32(v int32) {
498 u := uint32(v)
499 e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24))
500}
501
502func (e *encoder) addInt64(v int64) {
503 u := uint64(v)
504 e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24),
505 byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56))
506}
507
508func (e *encoder) addFloat64(v float64) {
509 e.addInt64(int64(math.Float64bits(v)))
510}
511
512func (e *encoder) addBytes(v ...byte) {
513 e.out = append(e.out, v...)
514}