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