-
Notifications
You must be signed in to change notification settings - Fork 219
/
bson.go
138 lines (127 loc) · 4.21 KB
/
bson.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package bson
// https://bsonspec.org/spec.html
import (
"embed"
"github.com/wader/fq/format"
"github.com/wader/fq/pkg/decode"
"github.com/wader/fq/pkg/interp"
"github.com/wader/fq/pkg/scalar"
)
//go:embed bson.jq
//go:embed bson.md
var bsonFS embed.FS
func init() {
interp.RegisterFormat(
format.BSON,
&decode.Format{
Description: "Binary JSON",
DecodeFn: decodeBSON,
Functions: []string{"torepr"},
})
interp.RegisterFS(bsonFS)
}
const (
elementTypeDouble = 0x01
elementTypeString = 0x02
elementTypeDocument = 0x03
elementTypeArray = 0x04
elementTypeBinary = 0x05
elementTypeUndefined = 0x06
elementTypeObjectID = 0x07
elementTypeBoolean = 0x08
elementTypeDatetime = 0x09
elementTypeNull = 0x0a
elementTypeRegexp = 0x0b
elementTypeJavaScript = 0x0d
elementTypeInt32 = 0x10
elementTypeTimestamp = 0x11
elementTypeInt64 = 0x12
elementTypeDecimal128 = 0x13
elementTypeMinKey = 0xFF
elementTypeMaxKey = 0x7f
)
var elementTypeMap = scalar.UintMap{
elementTypeDouble: {Sym: "double", Description: "64-bit binary floating point"},
elementTypeString: {Sym: "string", Description: "UTF-8 string"},
elementTypeDocument: {Sym: "document", Description: "Embedded document"},
elementTypeArray: {Sym: "array", Description: "Array"},
elementTypeBinary: {Sym: "binary", Description: "Binary data"},
elementTypeUndefined: {Sym: "undefined", Description: "Undefined (deprecated)"},
elementTypeObjectID: {Sym: "object_id", Description: "ObjectId"},
elementTypeBoolean: {Sym: "boolean", Description: "Boolean"},
elementTypeDatetime: {Sym: "datetime", Description: "UTC datetime"},
elementTypeNull: {Sym: "null", Description: "Null value"},
elementTypeRegexp: {Sym: "regexp", Description: "Regular expression"},
elementTypeJavaScript: {Sym: "javascript", Description: "JavaScript code"},
elementTypeInt32: {Sym: "int32", Description: "32-bit integer"},
elementTypeTimestamp: {Sym: "timestamp", Description: "Timestamp"},
elementTypeInt64: {Sym: "int64", Description: "64-bit integer"},
elementTypeDecimal128: {Sym: "decimal128", Description: "128-bit decimal floating point"},
elementTypeMinKey: {Sym: "minkey", Description: "Min key"},
elementTypeMaxKey: {Sym: "maxkey", Description: "Max key"},
}
func decodeBSONDocument(d *decode.D) {
size := d.FieldS32("size")
d.FramedFn((size-4)*8, func(d *decode.D) {
d.FieldArray("elements", func(d *decode.D) {
for d.BitsLeft() > 8 {
d.FieldStruct("element", func(d *decode.D) {
typ := d.FieldU8("type", elementTypeMap)
d.FieldUTF8Null("name")
switch typ {
case elementTypeDouble:
d.FieldF64("value")
case elementTypeString:
length := d.FieldU32("length")
d.FieldUTF8NullFixedLen("value", int(length))
case elementTypeDocument:
d.FieldStruct("value", decodeBSONDocument)
case elementTypeArray:
d.FieldStruct("value", decodeBSONDocument)
case elementTypeBinary:
length := d.FieldS32("length")
d.FieldU8("subtype")
d.FieldRawLen("value", length*8)
case elementTypeUndefined:
//deprecated
case elementTypeObjectID:
d.FieldRawLen("value", 12*8)
case elementTypeBoolean:
d.FieldU8("value")
case elementTypeDatetime:
d.FieldS64("value")
case elementTypeNull:
d.FieldValueAny("value", nil)
case elementTypeRegexp:
d.FieldUTF8Null("value")
d.FieldUTF8Null("options")
case elementTypeJavaScript:
length := d.FieldS32("length")
d.FieldUTF8NullFixedLen("value", int(length))
case elementTypeInt32:
d.FieldS32("value")
case elementTypeTimestamp:
d.FieldU64("value")
case elementTypeInt64:
d.FieldS64("value")
case elementTypeDecimal128:
// TODO: Parse the IEEE 754 decimal128 value.
d.FieldRawLen("value", 128)
case elementTypeMinKey:
d.FieldValueAny("value", nil)
case elementTypeMaxKey:
d.FieldValueAny("value", nil)
default:
d.FieldRawLen("value", d.BitsLeft())
}
})
}
})
d.FieldU8("terminator", d.UintValidate(0))
})
}
func decodeBSON(d *decode.D) any {
d.Endian = decode.LittleEndian
decodeBSONDocument(d)
return nil
}