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