1// Copyright (C) MongoDB, Inc. 2017-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7// Package bsoncore contains functions that can be used to encode and decode BSON
8// elements and values to or from a slice of bytes. These functions are aimed at
9// allowing low level manipulation of BSON and can be used to build a higher
10// level BSON library.
11//
12// The Read* functions within this package return the values of the element and
13// a boolean indicating if the values are valid. A boolean was used instead of
14// an error because any error that would be returned would be the same: not
15// enough bytes. This library attempts to do no validation, it will only return
16// false if there are not enough bytes for an item to be read. For example, the
17// ReadDocument function checks the length, if that length is larger than the
18// number of bytes availble, it will return false, if there are enough bytes, it
19// will return those bytes and true. It is the consumers responsibility to
20// validate those bytes.
21//
22// The Append* functions within this package will append the type value to the
23// given dst slice. If the slice has enough capacity, it will not grow the
24// slice. The Append*Element functions within this package operate in the same
25// way, but additionally append the BSON type and the key before the value.
26package bsoncore // import "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
27
28import (
29	"bytes"
30	"fmt"
31	"math"
32	"time"
33
34	"go.mongodb.org/mongo-driver/bson/bsontype"
35	"go.mongodb.org/mongo-driver/bson/primitive"
36)
37
38// AppendType will append t to dst and return the extended buffer.
39func AppendType(dst []byte, t bsontype.Type) []byte { return append(dst, byte(t)) }
40
41// AppendKey will append key to dst and return the extended buffer.
42func AppendKey(dst []byte, key string) []byte { return append(dst, key+string(0x00)...) }
43
44// AppendHeader will append Type t and key to dst and return the extended
45// buffer.
46func AppendHeader(dst []byte, t bsontype.Type, key string) []byte {
47	dst = AppendType(dst, t)
48	dst = append(dst, key...)
49	return append(dst, 0x00)
50	// return append(AppendType(dst, t), key+string(0x00)...)
51}
52
53// TODO(skriptble): All of the Read* functions should return src resliced to start just after what
54// was read.
55
56// ReadType will return the first byte of the provided []byte as a type. If
57// there is no availble byte, false is returned.
58func ReadType(src []byte) (bsontype.Type, []byte, bool) {
59	if len(src) < 1 {
60		return 0, src, false
61	}
62	return bsontype.Type(src[0]), src[1:], true
63}
64
65// ReadKey will read a key from src. The 0x00 byte will not be present
66// in the returned string. If there are not enough bytes available, false is
67// returned.
68func ReadKey(src []byte) (string, []byte, bool) { return readcstring(src) }
69
70// ReadKeyBytes will read a key from src as bytes. The 0x00 byte will
71// not be present in the returned string. If there are not enough bytes
72// available, false is returned.
73func ReadKeyBytes(src []byte) ([]byte, []byte, bool) { return readcstringbytes(src) }
74
75// ReadHeader will read a type byte and a key from src. If both of these
76// values cannot be read, false is returned.
77func ReadHeader(src []byte) (t bsontype.Type, key string, rem []byte, ok bool) {
78	t, rem, ok = ReadType(src)
79	if !ok {
80		return 0, "", src, false
81	}
82	key, rem, ok = ReadKey(rem)
83	if !ok {
84		return 0, "", src, false
85	}
86
87	return t, key, rem, true
88}
89
90// ReadHeaderBytes will read a type and a key from src and the remainder of the bytes
91// are returned as rem. If either the type or key cannot be red, ok will be false.
92func ReadHeaderBytes(src []byte) (header []byte, rem []byte, ok bool) {
93	if len(src) < 1 {
94		return nil, src, false
95	}
96	idx := bytes.IndexByte(src[1:], 0x00)
97	if idx == -1 {
98		return nil, src, false
99	}
100	return src[:idx], src[idx+1:], true
101}
102
103// ReadElement reads the next full element from src. It returns the element, the remaining bytes in
104// the slice, and a boolean indicating if the read was successful.
105func ReadElement(src []byte) (Element, []byte, bool) {
106	if len(src) < 1 {
107		return nil, src, false
108	}
109	t := bsontype.Type(src[0])
110	idx := bytes.IndexByte(src[1:], 0x00)
111	if idx == -1 {
112		return nil, src, false
113	}
114	length, ok := valueLength(src[idx+2:], t) // We add 2 here because we called IndexByte with src[1:]
115	if !ok {
116		return nil, src, false
117	}
118	elemLength := 1 + idx + 1 + int(length)
119	if elemLength > len(src) {
120		return nil, src, false
121	}
122	return src[:elemLength], src[elemLength:], true
123}
124
125// ReadValue reads the next value as the provided types and returns a Value, the remaining bytes,
126// and a boolean indicating if the read was successful.
127func ReadValue(src []byte, t bsontype.Type) (Value, []byte, bool) {
128	data, rem, ok := readValue(src, t)
129	if !ok {
130		return Value{}, src, false
131	}
132	return Value{Type: t, Data: data}, rem, true
133}
134
135// AppendDouble will append f to dst and return the extended buffer.
136func AppendDouble(dst []byte, f float64) []byte {
137	return appendu64(dst, math.Float64bits(f))
138}
139
140// AppendDoubleElement will append a BSON double element using key and f to dst
141// and return the extended buffer.
142func AppendDoubleElement(dst []byte, key string, f float64) []byte {
143	return AppendDouble(AppendHeader(dst, bsontype.Double, key), f)
144}
145
146// ReadDouble will read a float64 from src. If there are not enough bytes it
147// will return false.
148func ReadDouble(src []byte) (float64, []byte, bool) {
149	bits, src, ok := readu64(src)
150	if !ok {
151		return 0, src, false
152	}
153	return math.Float64frombits(bits), src, true
154}
155
156// AppendString will append s to dst and return the extended buffer.
157func AppendString(dst []byte, s string) []byte {
158	return appendstring(dst, s)
159}
160
161// AppendStringElement will append a BSON string element using key and val to dst
162// and return the extended buffer.
163func AppendStringElement(dst []byte, key, val string) []byte {
164	return AppendString(AppendHeader(dst, bsontype.String, key), val)
165}
166
167// ReadString will read a string from src. If there are not enough bytes it
168// will return false.
169func ReadString(src []byte) (string, []byte, bool) {
170	return readstring(src)
171}
172
173// AppendDocumentStart reserves a document's length and returns the index where the length begins.
174// This index can later be used to write the length of the document.
175//
176// TODO(skriptble): We really need AppendDocumentStart and AppendDocumentEnd.
177// AppendDocumentStart would handle calling ReserveLength and providing the index of the start of
178// the document. AppendDocumentEnd would handle taking that start index, adding the null byte,
179// calculating the length, and filling in the length at the start of the document.
180func AppendDocumentStart(dst []byte) (index int32, b []byte) { return ReserveLength(dst) }
181
182// AppendDocumentStartInline functions the same as AppendDocumentStart but takes a pointer to the
183// index int32 which allows this function to be used inline.
184func AppendDocumentStartInline(dst []byte, index *int32) []byte {
185	idx, doc := AppendDocumentStart(dst)
186	*index = idx
187	return doc
188}
189
190// AppendDocumentElementStart writes a document element header and then reserves the length bytes.
191func AppendDocumentElementStart(dst []byte, key string) (index int32, b []byte) {
192	return AppendDocumentStart(AppendHeader(dst, bsontype.EmbeddedDocument, key))
193}
194
195// AppendDocumentEnd writes the null byte for a document and updates the length of the document.
196// The index should be the beginning of the document's length bytes.
197func AppendDocumentEnd(dst []byte, index int32) ([]byte, error) {
198	if int(index) > len(dst)-4 {
199		return dst, fmt.Errorf("not enough bytes available after index to write length")
200	}
201	dst = append(dst, 0x00)
202	dst = UpdateLength(dst, index, int32(len(dst[index:])))
203	return dst, nil
204}
205
206// AppendDocument will append doc to dst and return the extended buffer.
207func AppendDocument(dst []byte, doc []byte) []byte { return append(dst, doc...) }
208
209// AppendDocumentElement will append a BSON embeded document element using key
210// and doc to dst and return the extended buffer.
211func AppendDocumentElement(dst []byte, key string, doc []byte) []byte {
212	return AppendDocument(AppendHeader(dst, bsontype.EmbeddedDocument, key), doc)
213}
214
215// BuildDocument will create a document with the given elements and will append it to dst.
216func BuildDocument(dst []byte, elems []byte) []byte {
217	idx, dst := ReserveLength(dst)
218	dst = append(dst, elems...)
219	dst = append(dst, 0x00)
220	dst = UpdateLength(dst, idx, int32(len(dst[idx:])))
221	return dst
222}
223
224// BuildDocumentFromElements will create a document with the given slice of elements and will append
225// it to dst and return the extended buffer.
226func BuildDocumentFromElements(dst []byte, elems ...[]byte) []byte {
227	idx, dst := ReserveLength(dst)
228	for _, elem := range elems {
229		dst = append(dst, elem...)
230	}
231	dst = append(dst, 0x00)
232	dst = UpdateLength(dst, idx, int32(len(dst[idx:])))
233	return dst
234}
235
236// ReadDocument will read a document from src. If there are not enough bytes it
237// will return false.
238func ReadDocument(src []byte) (doc Document, rem []byte, ok bool) { return readLengthBytes(src) }
239
240// AppendArrayStart appends the length bytes to an array and then returns the index of the start
241// of those length bytes.
242func AppendArrayStart(dst []byte) (index int32, b []byte) { return ReserveLength(dst) }
243
244// AppendArrayElementStart appends an array element header and then the length bytes for an array,
245// returning the index where the length starts.
246func AppendArrayElementStart(dst []byte, key string) (index int32, b []byte) {
247	return AppendArrayStart(AppendHeader(dst, bsontype.Array, key))
248}
249
250// AppendArrayEnd appends the null byte to an array and calculates the length, inserting that
251// calculated length starting at index.
252func AppendArrayEnd(dst []byte, index int32) ([]byte, error) { return AppendDocumentEnd(dst, index) }
253
254// AppendArray will append arr to dst and return the extended buffer.
255func AppendArray(dst []byte, arr []byte) []byte { return append(dst, arr...) }
256
257// AppendArrayElement will append a BSON array element using key and arr to dst
258// and return the extended buffer.
259func AppendArrayElement(dst []byte, key string, arr []byte) []byte {
260	return AppendArray(AppendHeader(dst, bsontype.Array, key), arr)
261}
262
263// ReadArray will read an array from src. If there are not enough bytes it
264// will return false.
265func ReadArray(src []byte) (arr Document, rem []byte, ok bool) { return readLengthBytes(src) }
266
267// AppendBinary will append subtype and b to dst and return the extended buffer.
268func AppendBinary(dst []byte, subtype byte, b []byte) []byte {
269	if subtype == 0x02 {
270		return appendBinarySubtype2(dst, subtype, b)
271	}
272	dst = append(appendLength(dst, int32(len(b))), subtype)
273	return append(dst, b...)
274}
275
276// AppendBinaryElement will append a BSON binary element using key, subtype, and
277// b to dst and return the extended buffer.
278func AppendBinaryElement(dst []byte, key string, subtype byte, b []byte) []byte {
279	return AppendBinary(AppendHeader(dst, bsontype.Binary, key), subtype, b)
280}
281
282// ReadBinary will read a subtype and bin from src. If there are not enough bytes it
283// will return false.
284func ReadBinary(src []byte) (subtype byte, bin []byte, rem []byte, ok bool) {
285	length, rem, ok := ReadLength(src)
286	if !ok {
287		return 0x00, nil, src, false
288	}
289	if len(rem) < 1 { // subtype
290		return 0x00, nil, src, false
291	}
292	subtype, rem = rem[0], rem[1:]
293
294	if len(rem) < int(length) {
295		return 0x00, nil, src, false
296	}
297
298	if subtype == 0x02 {
299		length, rem, ok = ReadLength(rem)
300		if !ok || len(rem) < int(length) {
301			return 0x00, nil, src, false
302		}
303	}
304
305	return subtype, rem[:length], rem[length:], true
306}
307
308// AppendUndefinedElement will append a BSON undefined element using key to dst
309// and return the extended buffer.
310func AppendUndefinedElement(dst []byte, key string) []byte {
311	return AppendHeader(dst, bsontype.Undefined, key)
312}
313
314// AppendObjectID will append oid to dst and return the extended buffer.
315func AppendObjectID(dst []byte, oid primitive.ObjectID) []byte { return append(dst, oid[:]...) }
316
317// AppendObjectIDElement will append a BSON ObjectID element using key and oid to dst
318// and return the extended buffer.
319func AppendObjectIDElement(dst []byte, key string, oid primitive.ObjectID) []byte {
320	return AppendObjectID(AppendHeader(dst, bsontype.ObjectID, key), oid)
321}
322
323// ReadObjectID will read an ObjectID from src. If there are not enough bytes it
324// will return false.
325func ReadObjectID(src []byte) (primitive.ObjectID, []byte, bool) {
326	if len(src) < 12 {
327		return primitive.ObjectID{}, src, false
328	}
329	var oid primitive.ObjectID
330	copy(oid[:], src[0:12])
331	return oid, src[12:], true
332}
333
334// AppendBoolean will append b to dst and return the extended buffer.
335func AppendBoolean(dst []byte, b bool) []byte {
336	if b {
337		return append(dst, 0x01)
338	}
339	return append(dst, 0x00)
340}
341
342// AppendBooleanElement will append a BSON boolean element using key and b to dst
343// and return the extended buffer.
344func AppendBooleanElement(dst []byte, key string, b bool) []byte {
345	return AppendBoolean(AppendHeader(dst, bsontype.Boolean, key), b)
346}
347
348// ReadBoolean will read a bool from src. If there are not enough bytes it
349// will return false.
350func ReadBoolean(src []byte) (bool, []byte, bool) {
351	if len(src) < 1 {
352		return false, src, false
353	}
354
355	return src[0] == 0x01, src[1:], true
356}
357
358// AppendDateTime will append dt to dst and return the extended buffer.
359func AppendDateTime(dst []byte, dt int64) []byte { return appendi64(dst, dt) }
360
361// AppendDateTimeElement will append a BSON datetime element using key and dt to dst
362// and return the extended buffer.
363func AppendDateTimeElement(dst []byte, key string, dt int64) []byte {
364	return AppendDateTime(AppendHeader(dst, bsontype.DateTime, key), dt)
365}
366
367// ReadDateTime will read an int64 datetime from src. If there are not enough bytes it
368// will return false.
369func ReadDateTime(src []byte) (int64, []byte, bool) { return readi64(src) }
370
371// AppendTime will append time as a BSON DateTime to dst and return the extended buffer.
372func AppendTime(dst []byte, t time.Time) []byte {
373	return AppendDateTime(dst, t.Unix()*1000+int64(t.Nanosecond()/1e6))
374}
375
376// AppendTimeElement will append a BSON datetime element using key and dt to dst
377// and return the extended buffer.
378func AppendTimeElement(dst []byte, key string, t time.Time) []byte {
379	return AppendTime(AppendHeader(dst, bsontype.DateTime, key), t)
380}
381
382// ReadTime will read an time.Time datetime from src. If there are not enough bytes it
383// will return false.
384func ReadTime(src []byte) (time.Time, []byte, bool) {
385	dt, rem, ok := readi64(src)
386	return time.Unix(dt/1e3, dt%1e3*1e6), rem, ok
387}
388
389// AppendNullElement will append a BSON null element using key to dst
390// and return the extended buffer.
391func AppendNullElement(dst []byte, key string) []byte { return AppendHeader(dst, bsontype.Null, key) }
392
393// AppendRegex will append pattern and options to dst and return the extended buffer.
394func AppendRegex(dst []byte, pattern, options string) []byte {
395	return append(dst, pattern+string(0x00)+options+string(0x00)...)
396}
397
398// AppendRegexElement will append a BSON regex element using key, pattern, and
399// options to dst and return the extended buffer.
400func AppendRegexElement(dst []byte, key, pattern, options string) []byte {
401	return AppendRegex(AppendHeader(dst, bsontype.Regex, key), pattern, options)
402}
403
404// ReadRegex will read a pattern and options from src. If there are not enough bytes it
405// will return false.
406func ReadRegex(src []byte) (pattern, options string, rem []byte, ok bool) {
407	pattern, rem, ok = readcstring(src)
408	if !ok {
409		return "", "", src, false
410	}
411	options, rem, ok = readcstring(rem)
412	if !ok {
413		return "", "", src, false
414	}
415	return pattern, options, rem, true
416}
417
418// AppendDBPointer will append ns and oid to dst and return the extended buffer.
419func AppendDBPointer(dst []byte, ns string, oid primitive.ObjectID) []byte {
420	return append(appendstring(dst, ns), oid[:]...)
421}
422
423// AppendDBPointerElement will append a BSON DBPointer element using key, ns,
424// and oid to dst and return the extended buffer.
425func AppendDBPointerElement(dst []byte, key, ns string, oid primitive.ObjectID) []byte {
426	return AppendDBPointer(AppendHeader(dst, bsontype.DBPointer, key), ns, oid)
427}
428
429// ReadDBPointer will read a ns and oid from src. If there are not enough bytes it
430// will return false.
431func ReadDBPointer(src []byte) (ns string, oid primitive.ObjectID, rem []byte, ok bool) {
432	ns, rem, ok = readstring(src)
433	if !ok {
434		return "", primitive.ObjectID{}, src, false
435	}
436	oid, rem, ok = ReadObjectID(rem)
437	if !ok {
438		return "", primitive.ObjectID{}, src, false
439	}
440	return ns, oid, rem, true
441}
442
443// AppendJavaScript will append js to dst and return the extended buffer.
444func AppendJavaScript(dst []byte, js string) []byte { return appendstring(dst, js) }
445
446// AppendJavaScriptElement will append a BSON JavaScript element using key and
447// js to dst and return the extended buffer.
448func AppendJavaScriptElement(dst []byte, key, js string) []byte {
449	return AppendJavaScript(AppendHeader(dst, bsontype.JavaScript, key), js)
450}
451
452// ReadJavaScript will read a js string from src. If there are not enough bytes it
453// will return false.
454func ReadJavaScript(src []byte) (js string, rem []byte, ok bool) { return readstring(src) }
455
456// AppendSymbol will append symbol to dst and return the extended buffer.
457func AppendSymbol(dst []byte, symbol string) []byte { return appendstring(dst, symbol) }
458
459// AppendSymbolElement will append a BSON symbol element using key and symbol to dst
460// and return the extended buffer.
461func AppendSymbolElement(dst []byte, key, symbol string) []byte {
462	return AppendSymbol(AppendHeader(dst, bsontype.Symbol, key), symbol)
463}
464
465// ReadSymbol will read a symbol string from src. If there are not enough bytes it
466// will return false.
467func ReadSymbol(src []byte) (symbol string, rem []byte, ok bool) { return readstring(src) }
468
469// AppendCodeWithScope will append code and scope to dst and return the extended buffer.
470func AppendCodeWithScope(dst []byte, code string, scope []byte) []byte {
471	length := int32(4 + 4 + len(code) + 1 + len(scope)) // length of cws, length of code, code, 0x00, scope
472	dst = appendLength(dst, length)
473
474	return append(appendstring(dst, code), scope...)
475}
476
477// AppendCodeWithScopeElement will append a BSON code with scope element using
478// key, code, and scope to dst
479// and return the extended buffer.
480func AppendCodeWithScopeElement(dst []byte, key, code string, scope []byte) []byte {
481	return AppendCodeWithScope(AppendHeader(dst, bsontype.CodeWithScope, key), code, scope)
482}
483
484// ReadCodeWithScope will read code and scope from src. If there are not enough bytes it
485// will return false.
486func ReadCodeWithScope(src []byte) (code string, scope []byte, rem []byte, ok bool) {
487	length, rem, ok := ReadLength(src)
488	if !ok || len(src) < int(length) {
489		return "", nil, src, false
490	}
491
492	code, rem, ok = readstring(rem)
493	if !ok {
494		return "", nil, src, false
495	}
496
497	scope, rem, ok = ReadDocument(rem)
498	if !ok {
499		return "", nil, src, false
500	}
501	return code, scope, rem, true
502}
503
504// AppendInt32 will append i32 to dst and return the extended buffer.
505func AppendInt32(dst []byte, i32 int32) []byte { return appendi32(dst, i32) }
506
507// AppendInt32Element will append a BSON int32 element using key and i32 to dst
508// and return the extended buffer.
509func AppendInt32Element(dst []byte, key string, i32 int32) []byte {
510	return AppendInt32(AppendHeader(dst, bsontype.Int32, key), i32)
511}
512
513// ReadInt32 will read an int32 from src. If there are not enough bytes it
514// will return false.
515func ReadInt32(src []byte) (int32, []byte, bool) { return readi32(src) }
516
517// AppendTimestamp will append t and i to dst and return the extended buffer.
518func AppendTimestamp(dst []byte, t, i uint32) []byte {
519	return appendu32(appendu32(dst, i), t) // i is the lower 4 bytes, t is the higher 4 bytes
520}
521
522// AppendTimestampElement will append a BSON timestamp element using key, t, and
523// i to dst and return the extended buffer.
524func AppendTimestampElement(dst []byte, key string, t, i uint32) []byte {
525	return AppendTimestamp(AppendHeader(dst, bsontype.Timestamp, key), t, i)
526}
527
528// ReadTimestamp will read t and i from src. If there are not enough bytes it
529// will return false.
530func ReadTimestamp(src []byte) (t, i uint32, rem []byte, ok bool) {
531	i, rem, ok = readu32(src)
532	if !ok {
533		return 0, 0, src, false
534	}
535	t, rem, ok = readu32(rem)
536	if !ok {
537		return 0, 0, src, false
538	}
539	return t, i, rem, true
540}
541
542// AppendInt64 will append i64 to dst and return the extended buffer.
543func AppendInt64(dst []byte, i64 int64) []byte { return appendi64(dst, i64) }
544
545// AppendInt64Element will append a BSON int64 element using key and i64 to dst
546// and return the extended buffer.
547func AppendInt64Element(dst []byte, key string, i64 int64) []byte {
548	return AppendInt64(AppendHeader(dst, bsontype.Int64, key), i64)
549}
550
551// ReadInt64 will read an int64 from src. If there are not enough bytes it
552// will return false.
553func ReadInt64(src []byte) (int64, []byte, bool) { return readi64(src) }
554
555// AppendDecimal128 will append d128 to dst and return the extended buffer.
556func AppendDecimal128(dst []byte, d128 primitive.Decimal128) []byte {
557	high, low := d128.GetBytes()
558	return appendu64(appendu64(dst, low), high)
559}
560
561// AppendDecimal128Element will append a BSON primitive.28 element using key and
562// d128 to dst and return the extended buffer.
563func AppendDecimal128Element(dst []byte, key string, d128 primitive.Decimal128) []byte {
564	return AppendDecimal128(AppendHeader(dst, bsontype.Decimal128, key), d128)
565}
566
567// ReadDecimal128 will read a primitive.Decimal128 from src. If there are not enough bytes it
568// will return false.
569func ReadDecimal128(src []byte) (primitive.Decimal128, []byte, bool) {
570	l, rem, ok := readu64(src)
571	if !ok {
572		return primitive.Decimal128{}, src, false
573	}
574
575	h, rem, ok := readu64(rem)
576	if !ok {
577		return primitive.Decimal128{}, src, false
578	}
579
580	return primitive.NewDecimal128(h, l), rem, true
581}
582
583// AppendMaxKeyElement will append a BSON max key element using key to dst
584// and return the extended buffer.
585func AppendMaxKeyElement(dst []byte, key string) []byte {
586	return AppendHeader(dst, bsontype.MaxKey, key)
587}
588
589// AppendMinKeyElement will append a BSON min key element using key to dst
590// and return the extended buffer.
591func AppendMinKeyElement(dst []byte, key string) []byte {
592	return AppendHeader(dst, bsontype.MinKey, key)
593}
594
595// EqualValue will return true if the two values are equal.
596func EqualValue(t1, t2 bsontype.Type, v1, v2 []byte) bool {
597	if t1 != t2 {
598		return false
599	}
600	v1, _, ok := readValue(v1, t1)
601	if !ok {
602		return false
603	}
604	v2, _, ok = readValue(v2, t2)
605	if !ok {
606		return false
607	}
608	return bytes.Equal(v1, v2)
609}
610
611// valueLength will determine the length of the next value contained in src as if it
612// is type t. The returned bool will be false if there are not enough bytes in src for
613// a value of type t.
614func valueLength(src []byte, t bsontype.Type) (int32, bool) {
615	var length int32
616	ok := true
617	switch t {
618	case bsontype.Array, bsontype.EmbeddedDocument, bsontype.CodeWithScope:
619		length, _, ok = ReadLength(src)
620	case bsontype.Binary:
621		length, _, ok = ReadLength(src)
622		length += 4 + 1 // binary length + subtype byte
623	case bsontype.Boolean:
624		length = 1
625	case bsontype.DBPointer:
626		length, _, ok = ReadLength(src)
627		length += 4 + 12 // string length + ObjectID length
628	case bsontype.DateTime, bsontype.Double, bsontype.Int64, bsontype.Timestamp:
629		length = 8
630	case bsontype.Decimal128:
631		length = 16
632	case bsontype.Int32:
633		length = 4
634	case bsontype.JavaScript, bsontype.String, bsontype.Symbol:
635		length, _, ok = ReadLength(src)
636		length += 4
637	case bsontype.MaxKey, bsontype.MinKey, bsontype.Null, bsontype.Undefined:
638		length = 0
639	case bsontype.ObjectID:
640		length = 12
641	case bsontype.Regex:
642		regex := bytes.IndexByte(src, 0x00)
643		if regex < 0 {
644			ok = false
645			break
646		}
647		pattern := bytes.IndexByte(src[regex+1:], 0x00)
648		if pattern < 0 {
649			ok = false
650			break
651		}
652		length = int32(int64(regex) + 1 + int64(pattern) + 1)
653	default:
654		ok = false
655	}
656
657	return length, ok
658}
659
660func readValue(src []byte, t bsontype.Type) ([]byte, []byte, bool) {
661	length, ok := valueLength(src, t)
662	if !ok || int(length) > len(src) {
663		return nil, src, false
664	}
665
666	return src[:length], src[length:], true
667}
668
669// ReserveLength reserves the space required for length and returns the index where to write the length
670// and the []byte with reserved space.
671func ReserveLength(dst []byte) (int32, []byte) {
672	index := len(dst)
673	return int32(index), append(dst, 0x00, 0x00, 0x00, 0x00)
674}
675
676// UpdateLength updates the length at index with length and returns the []byte.
677func UpdateLength(dst []byte, index, length int32) []byte {
678	dst[index] = byte(length)
679	dst[index+1] = byte(length >> 8)
680	dst[index+2] = byte(length >> 16)
681	dst[index+3] = byte(length >> 24)
682	return dst
683}
684
685func appendLength(dst []byte, l int32) []byte { return appendi32(dst, l) }
686
687func appendi32(dst []byte, i32 int32) []byte {
688	return append(dst, byte(i32), byte(i32>>8), byte(i32>>16), byte(i32>>24))
689}
690
691// ReadLength reads an int32 length from src and returns the length and the remaining bytes. If
692// there aren't enough bytes to read a valid length, src is returned unomdified and the returned
693// bool will be false.
694func ReadLength(src []byte) (int32, []byte, bool) { return readi32(src) }
695
696func readi32(src []byte) (int32, []byte, bool) {
697	if len(src) < 4 {
698		return 0, src, false
699	}
700
701	return (int32(src[0]) | int32(src[1])<<8 | int32(src[2])<<16 | int32(src[3])<<24), src[4:], true
702}
703
704func appendi64(dst []byte, i64 int64) []byte {
705	return append(dst,
706		byte(i64), byte(i64>>8), byte(i64>>16), byte(i64>>24),
707		byte(i64>>32), byte(i64>>40), byte(i64>>48), byte(i64>>56),
708	)
709}
710
711func readi64(src []byte) (int64, []byte, bool) {
712	if len(src) < 8 {
713		return 0, src, false
714	}
715	i64 := (int64(src[0]) | int64(src[1])<<8 | int64(src[2])<<16 | int64(src[3])<<24 |
716		int64(src[4])<<32 | int64(src[5])<<40 | int64(src[6])<<48 | int64(src[7])<<56)
717	return i64, src[8:], true
718}
719
720func appendu32(dst []byte, u32 uint32) []byte {
721	return append(dst, byte(u32), byte(u32>>8), byte(u32>>16), byte(u32>>24))
722}
723
724func readu32(src []byte) (uint32, []byte, bool) {
725	if len(src) < 4 {
726		return 0, src, false
727	}
728
729	return (uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24), src[4:], true
730}
731
732func appendu64(dst []byte, u64 uint64) []byte {
733	return append(dst,
734		byte(u64), byte(u64>>8), byte(u64>>16), byte(u64>>24),
735		byte(u64>>32), byte(u64>>40), byte(u64>>48), byte(u64>>56),
736	)
737}
738
739func readu64(src []byte) (uint64, []byte, bool) {
740	if len(src) < 8 {
741		return 0, src, false
742	}
743	u64 := (uint64(src[0]) | uint64(src[1])<<8 | uint64(src[2])<<16 | uint64(src[3])<<24 |
744		uint64(src[4])<<32 | uint64(src[5])<<40 | uint64(src[6])<<48 | uint64(src[7])<<56)
745	return u64, src[8:], true
746}
747
748// keep in sync with readcstringbytes
749func readcstring(src []byte) (string, []byte, bool) {
750	idx := bytes.IndexByte(src, 0x00)
751	if idx < 0 {
752		return "", src, false
753	}
754	return string(src[:idx]), src[idx+1:], true
755}
756
757// keep in sync with readcstring
758func readcstringbytes(src []byte) ([]byte, []byte, bool) {
759	idx := bytes.IndexByte(src, 0x00)
760	if idx < 0 {
761		return nil, src, false
762	}
763	return src[:idx], src[idx+1:], true
764}
765
766func appendstring(dst []byte, s string) []byte {
767	l := int32(len(s) + 1)
768	dst = appendLength(dst, l)
769	dst = append(dst, s...)
770	return append(dst, 0x00)
771}
772
773func readstring(src []byte) (string, []byte, bool) {
774	l, rem, ok := ReadLength(src)
775	if !ok {
776		return "", src, false
777	}
778	if len(src[4:]) < int(l) {
779		return "", src, false
780	}
781
782	return string(rem[:l-1]), rem[l:], true
783}
784
785// readLengthBytes attempts to read a length and that number of bytes. This
786// function requires that the length include the four bytes for itself.
787func readLengthBytes(src []byte) ([]byte, []byte, bool) {
788	l, _, ok := ReadLength(src)
789	if !ok {
790		return nil, src, false
791	}
792	if len(src) < int(l) {
793		return nil, src, false
794	}
795	return src[:l], src[l:], true
796}
797
798func appendBinarySubtype2(dst []byte, subtype byte, b []byte) []byte {
799	dst = appendLength(dst, int32(len(b)+4)) // The bytes we'll encode need to be 4 larger for the length bytes
800	dst = append(dst, subtype)
801	dst = appendLength(dst, int32(len(b)))
802	return append(dst, b...)
803}
804