...

Source file src/go.mongodb.org/mongo-driver/x/bsonx/bsoncore/bsoncore.go

Documentation: go.mongodb.org/mongo-driver/x/bsonx/bsoncore

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

View as plain text