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