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