1
2
3
4
5
6
7 package bsoncore
8
9 import (
10 "errors"
11 "fmt"
12 "io"
13 "strconv"
14 "strings"
15
16 "go.mongodb.org/mongo-driver/bson/bsontype"
17 )
18
19
20 type ValidationError string
21
22 func (ve ValidationError) Error() string { return string(ve) }
23
24
25
26 func NewDocumentLengthError(length, rem int) error {
27 return lengthError("document", length, rem)
28 }
29
30 func lengthError(bufferType string, length, rem int) error {
31 return ValidationError(fmt.Sprintf("%v length exceeds available bytes. length=%d remainingBytes=%d",
32 bufferType, length, rem))
33 }
34
35
36 type InsufficientBytesError struct {
37 Source []byte
38 Remaining []byte
39 }
40
41
42
43 func NewInsufficientBytesError(src, rem []byte) InsufficientBytesError {
44 return InsufficientBytesError{Source: src, Remaining: rem}
45 }
46
47
48 func (ibe InsufficientBytesError) Error() string {
49 return "too few bytes to read next component"
50 }
51
52
53 func (ibe InsufficientBytesError) Equal(err2 error) bool {
54 switch err2.(type) {
55 case InsufficientBytesError:
56 return true
57 default:
58 return false
59 }
60 }
61
62
63
64 type InvalidDepthTraversalError struct {
65 Key string
66 Type bsontype.Type
67 }
68
69 func (idte InvalidDepthTraversalError) Error() string {
70 return fmt.Sprintf(
71 "attempt to traverse into %s, but it's type is %s, not %s nor %s",
72 idte.Key, idte.Type, bsontype.EmbeddedDocument, bsontype.Array,
73 )
74 }
75
76
77 const ErrMissingNull ValidationError = "document or array end is missing null byte"
78
79
80
81 const ErrInvalidLength ValidationError = "document or array length is invalid"
82
83
84 var ErrNilReader = errors.New("nil reader")
85
86
87 var ErrEmptyKey = errors.New("empty key provided")
88
89
90 var ErrElementNotFound = errors.New("element not found")
91
92
93 var ErrOutOfBounds = errors.New("out of bounds")
94
95
96 type Document []byte
97
98
99
100 func NewDocumentFromReader(r io.Reader) (Document, error) {
101 return newBufferFromReader(r)
102 }
103
104 func newBufferFromReader(r io.Reader) ([]byte, error) {
105 if r == nil {
106 return nil, ErrNilReader
107 }
108
109 var lengthBytes [4]byte
110
111
112 _, err := io.ReadFull(r, lengthBytes[:])
113 if err != nil {
114 return nil, err
115 }
116
117 length, _, _ := readi32(lengthBytes[:])
118 if length < 0 {
119 return nil, ErrInvalidLength
120 }
121 buffer := make([]byte, length)
122
123 copy(buffer, lengthBytes[:])
124
125 _, err = io.ReadFull(r, buffer[4:])
126 if err != nil {
127 return nil, err
128 }
129
130 if buffer[length-1] != 0x00 {
131 return nil, ErrMissingNull
132 }
133
134 return buffer, nil
135 }
136
137
138
139
140
141 func (d Document) Lookup(key ...string) Value {
142 val, _ := d.LookupErr(key...)
143 return val
144 }
145
146
147 func (d Document) LookupErr(key ...string) (Value, error) {
148 if len(key) < 1 {
149 return Value{}, ErrEmptyKey
150 }
151 length, rem, ok := ReadLength(d)
152 if !ok {
153 return Value{}, NewInsufficientBytesError(d, rem)
154 }
155
156 length -= 4
157
158 var elem Element
159 for length > 1 {
160 elem, rem, ok = ReadElement(rem)
161 length -= int32(len(elem))
162 if !ok {
163 return Value{}, NewInsufficientBytesError(d, rem)
164 }
165
166 if string(elem.KeyBytes()) != key[0] {
167 continue
168 }
169 if len(key) > 1 {
170 tt := bsontype.Type(elem[0])
171 switch tt {
172 case bsontype.EmbeddedDocument:
173 val, err := elem.Value().Document().LookupErr(key[1:]...)
174 if err != nil {
175 return Value{}, err
176 }
177 return val, nil
178 case bsontype.Array:
179
180 val, err := Document(elem.Value().Array()).LookupErr(key[1:]...)
181 if err != nil {
182 return Value{}, err
183 }
184 return val, nil
185 default:
186 return Value{}, InvalidDepthTraversalError{Key: elem.Key(), Type: tt}
187 }
188 }
189 return elem.ValueErr()
190 }
191 return Value{}, ErrElementNotFound
192 }
193
194
195
196 func (d Document) Index(index uint) Element {
197 elem, err := d.IndexErr(index)
198 if err != nil {
199 panic(err)
200 }
201 return elem
202 }
203
204
205 func (d Document) IndexErr(index uint) (Element, error) {
206 return indexErr(d, index)
207 }
208
209 func indexErr(b []byte, index uint) (Element, error) {
210 length, rem, ok := ReadLength(b)
211 if !ok {
212 return nil, NewInsufficientBytesError(b, rem)
213 }
214
215 length -= 4
216
217 var current uint
218 var elem Element
219 for length > 1 {
220 elem, rem, ok = ReadElement(rem)
221 length -= int32(len(elem))
222 if !ok {
223 return nil, NewInsufficientBytesError(b, rem)
224 }
225 if current != index {
226 current++
227 continue
228 }
229 return elem, nil
230 }
231 return nil, ErrOutOfBounds
232 }
233
234
235
236 func (d Document) DebugString() string {
237 if len(d) < 5 {
238 return "<malformed>"
239 }
240 var buf strings.Builder
241 buf.WriteString("Document")
242 length, rem, _ := ReadLength(d)
243 buf.WriteByte('(')
244 buf.WriteString(strconv.Itoa(int(length)))
245 length -= 4
246 buf.WriteString("){")
247 var elem Element
248 var ok bool
249 for length > 1 {
250 elem, rem, ok = ReadElement(rem)
251 length -= int32(len(elem))
252 if !ok {
253 buf.WriteString(fmt.Sprintf("<malformed (%d)>", length))
254 break
255 }
256 buf.WriteString(elem.DebugString())
257 }
258 buf.WriteByte('}')
259
260 return buf.String()
261 }
262
263
264
265 func (d Document) String() string {
266 if len(d) < 5 {
267 return ""
268 }
269 var buf strings.Builder
270 buf.WriteByte('{')
271
272 length, rem, _ := ReadLength(d)
273
274 length -= 4
275
276 var elem Element
277 var ok bool
278 first := true
279 for length > 1 {
280 if !first {
281 buf.WriteByte(',')
282 }
283 elem, rem, ok = ReadElement(rem)
284 length -= int32(len(elem))
285 if !ok {
286 return ""
287 }
288 buf.WriteString(elem.String())
289 first = false
290 }
291 buf.WriteByte('}')
292
293 return buf.String()
294 }
295
296
297
298
299 func (d Document) Elements() ([]Element, error) {
300 length, rem, ok := ReadLength(d)
301 if !ok {
302 return nil, NewInsufficientBytesError(d, rem)
303 }
304
305 length -= 4
306
307 var elem Element
308 var elems []Element
309 for length > 1 {
310 elem, rem, ok = ReadElement(rem)
311 length -= int32(len(elem))
312 if !ok {
313 return elems, NewInsufficientBytesError(d, rem)
314 }
315 if err := elem.Validate(); err != nil {
316 return elems, err
317 }
318 elems = append(elems, elem)
319 }
320 return elems, nil
321 }
322
323
324
325
326 func (d Document) Values() ([]Value, error) {
327 return values(d)
328 }
329
330 func values(b []byte) ([]Value, error) {
331 length, rem, ok := ReadLength(b)
332 if !ok {
333 return nil, NewInsufficientBytesError(b, rem)
334 }
335
336 length -= 4
337
338 var elem Element
339 var vals []Value
340 for length > 1 {
341 elem, rem, ok = ReadElement(rem)
342 length -= int32(len(elem))
343 if !ok {
344 return vals, NewInsufficientBytesError(b, rem)
345 }
346 if err := elem.Value().Validate(); err != nil {
347 return vals, err
348 }
349 vals = append(vals, elem.Value())
350 }
351 return vals, nil
352 }
353
354
355 func (d Document) Validate() error {
356 length, rem, ok := ReadLength(d)
357 if !ok {
358 return NewInsufficientBytesError(d, rem)
359 }
360 if int(length) > len(d) {
361 return NewDocumentLengthError(int(length), len(d))
362 }
363 if d[length-1] != 0x00 {
364 return ErrMissingNull
365 }
366
367 length -= 4
368 var elem Element
369
370 for length > 1 {
371 elem, rem, ok = ReadElement(rem)
372 length -= int32(len(elem))
373 if !ok {
374 return NewInsufficientBytesError(d, rem)
375 }
376 err := elem.Validate()
377 if err != nil {
378 return err
379 }
380 }
381
382 if len(rem) < 1 || rem[0] != 0x00 {
383 return ErrMissingNull
384 }
385 return nil
386 }
387
View as plain text