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