Don Newton | 379ae25 | 2019-04-01 12:17:06 -0400 | [diff] [blame^] | 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. |
| 26 | package bsoncore |
| 27 | |
| 28 | import ( |
| 29 | "bytes" |
| 30 | "fmt" |
| 31 | "math" |
| 32 | "time" |
| 33 | |
| 34 | "github.com/mongodb/mongo-go-driver/bson/bsontype" |
| 35 | "github.com/mongodb/mongo-go-driver/bson/primitive" |
| 36 | ) |
| 37 | |
| 38 | // AppendType will append t to dst and return the extended buffer. |
| 39 | func 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. |
| 42 | func 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. |
| 46 | func 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. |
| 58 | func 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. |
| 68 | func 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. |
| 73 | func 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. |
| 77 | func 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. |
| 92 | func 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. |
| 105 | func 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. |
| 127 | func 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. |
| 136 | func 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. |
| 142 | func 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. |
| 148 | func 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. |
| 157 | func 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. |
| 163 | func 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. |
| 169 | func 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. |
| 180 | func 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. |
| 184 | func 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. |
| 191 | func 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. |
| 197 | func 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. |
| 207 | func 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. |
| 211 | func 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. |
| 216 | func 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 | // ReadDocument will read a document from src. If there are not enough bytes it |
| 225 | // will return false. |
| 226 | func ReadDocument(src []byte) (doc Document, rem []byte, ok bool) { return readLengthBytes(src) } |
| 227 | |
| 228 | // AppendArrayStart appends the length bytes to an array and then returns the index of the start |
| 229 | // of those length bytes. |
| 230 | func AppendArrayStart(dst []byte) (index int32, b []byte) { return ReserveLength(dst) } |
| 231 | |
| 232 | // AppendArrayElementStart appends an array element header and then the length bytes for an array, |
| 233 | // returning the index where the length starts. |
| 234 | func AppendArrayElementStart(dst []byte, key string) (index int32, b []byte) { |
| 235 | return AppendArrayStart(AppendHeader(dst, bsontype.Array, key)) |
| 236 | } |
| 237 | |
| 238 | // AppendArrayEnd appends the null byte to an array and calculates the length, inserting that |
| 239 | // calculated length starting at index. |
| 240 | func AppendArrayEnd(dst []byte, index int32) ([]byte, error) { return AppendDocumentEnd(dst, index) } |
| 241 | |
| 242 | // AppendArray will append arr to dst and return the extended buffer. |
| 243 | func AppendArray(dst []byte, arr []byte) []byte { return append(dst, arr...) } |
| 244 | |
| 245 | // AppendArrayElement will append a BSON array element using key and arr to dst |
| 246 | // and return the extended buffer. |
| 247 | func AppendArrayElement(dst []byte, key string, arr []byte) []byte { |
| 248 | return AppendArray(AppendHeader(dst, bsontype.Array, key), arr) |
| 249 | } |
| 250 | |
| 251 | // ReadArray will read an array from src. If there are not enough bytes it |
| 252 | // will return false. |
| 253 | func ReadArray(src []byte) (arr Document, rem []byte, ok bool) { return readLengthBytes(src) } |
| 254 | |
| 255 | // AppendBinary will append subtype and b to dst and return the extended buffer. |
| 256 | func AppendBinary(dst []byte, subtype byte, b []byte) []byte { |
| 257 | if subtype == 0x02 { |
| 258 | return appendBinarySubtype2(dst, subtype, b) |
| 259 | } |
| 260 | dst = append(appendLength(dst, int32(len(b))), subtype) |
| 261 | return append(dst, b...) |
| 262 | } |
| 263 | |
| 264 | // AppendBinaryElement will append a BSON binary element using key, subtype, and |
| 265 | // b to dst and return the extended buffer. |
| 266 | func AppendBinaryElement(dst []byte, key string, subtype byte, b []byte) []byte { |
| 267 | return AppendBinary(AppendHeader(dst, bsontype.Binary, key), subtype, b) |
| 268 | } |
| 269 | |
| 270 | // ReadBinary will read a subtype and bin from src. If there are not enough bytes it |
| 271 | // will return false. |
| 272 | func ReadBinary(src []byte) (subtype byte, bin []byte, rem []byte, ok bool) { |
| 273 | length, rem, ok := ReadLength(src) |
| 274 | if !ok { |
| 275 | return 0x00, nil, src, false |
| 276 | } |
| 277 | if len(rem) < 1 { // subtype |
| 278 | return 0x00, nil, src, false |
| 279 | } |
| 280 | subtype, rem = rem[0], rem[1:] |
| 281 | |
| 282 | if len(rem) < int(length) { |
| 283 | return 0x00, nil, src, false |
| 284 | } |
| 285 | |
| 286 | if subtype == 0x02 { |
| 287 | length, rem, ok = ReadLength(rem) |
| 288 | if !ok || len(rem) < int(length) { |
| 289 | return 0x00, nil, src, false |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | return subtype, rem[:length], rem[length:], true |
| 294 | } |
| 295 | |
| 296 | // AppendUndefinedElement will append a BSON undefined element using key to dst |
| 297 | // and return the extended buffer. |
| 298 | func AppendUndefinedElement(dst []byte, key string) []byte { |
| 299 | return AppendHeader(dst, bsontype.Undefined, key) |
| 300 | } |
| 301 | |
| 302 | // AppendObjectID will append oid to dst and return the extended buffer. |
| 303 | func AppendObjectID(dst []byte, oid primitive.ObjectID) []byte { return append(dst, oid[:]...) } |
| 304 | |
| 305 | // AppendObjectIDElement will append a BSON ObjectID element using key and oid to dst |
| 306 | // and return the extended buffer. |
| 307 | func AppendObjectIDElement(dst []byte, key string, oid primitive.ObjectID) []byte { |
| 308 | return AppendObjectID(AppendHeader(dst, bsontype.ObjectID, key), oid) |
| 309 | } |
| 310 | |
| 311 | // ReadObjectID will read an ObjectID from src. If there are not enough bytes it |
| 312 | // will return false. |
| 313 | func ReadObjectID(src []byte) (primitive.ObjectID, []byte, bool) { |
| 314 | if len(src) < 12 { |
| 315 | return primitive.ObjectID{}, src, false |
| 316 | } |
| 317 | var oid primitive.ObjectID |
| 318 | copy(oid[:], src[0:12]) |
| 319 | return oid, src[12:], true |
| 320 | } |
| 321 | |
| 322 | // AppendBoolean will append b to dst and return the extended buffer. |
| 323 | func AppendBoolean(dst []byte, b bool) []byte { |
| 324 | if b { |
| 325 | return append(dst, 0x01) |
| 326 | } |
| 327 | return append(dst, 0x00) |
| 328 | } |
| 329 | |
| 330 | // AppendBooleanElement will append a BSON boolean element using key and b to dst |
| 331 | // and return the extended buffer. |
| 332 | func AppendBooleanElement(dst []byte, key string, b bool) []byte { |
| 333 | return AppendBoolean(AppendHeader(dst, bsontype.Boolean, key), b) |
| 334 | } |
| 335 | |
| 336 | // ReadBoolean will read a bool from src. If there are not enough bytes it |
| 337 | // will return false. |
| 338 | func ReadBoolean(src []byte) (bool, []byte, bool) { |
| 339 | if len(src) < 1 { |
| 340 | return false, src, false |
| 341 | } |
| 342 | |
| 343 | return src[0] == 0x01, src[1:], true |
| 344 | } |
| 345 | |
| 346 | // AppendDateTime will append dt to dst and return the extended buffer. |
| 347 | func AppendDateTime(dst []byte, dt int64) []byte { return appendi64(dst, dt) } |
| 348 | |
| 349 | // AppendDateTimeElement will append a BSON datetime element using key and dt to dst |
| 350 | // and return the extended buffer. |
| 351 | func AppendDateTimeElement(dst []byte, key string, dt int64) []byte { |
| 352 | return AppendDateTime(AppendHeader(dst, bsontype.DateTime, key), dt) |
| 353 | } |
| 354 | |
| 355 | // ReadDateTime will read an int64 datetime from src. If there are not enough bytes it |
| 356 | // will return false. |
| 357 | func ReadDateTime(src []byte) (int64, []byte, bool) { return readi64(src) } |
| 358 | |
| 359 | // AppendTime will append time as a BSON DateTime to dst and return the extended buffer. |
| 360 | func AppendTime(dst []byte, t time.Time) []byte { |
| 361 | return AppendDateTime(dst, t.Unix()*1000+int64(t.Nanosecond()/1e6)) |
| 362 | } |
| 363 | |
| 364 | // AppendTimeElement will append a BSON datetime element using key and dt to dst |
| 365 | // and return the extended buffer. |
| 366 | func AppendTimeElement(dst []byte, key string, t time.Time) []byte { |
| 367 | return AppendTime(AppendHeader(dst, bsontype.DateTime, key), t) |
| 368 | } |
| 369 | |
| 370 | // ReadTime will read an time.Time datetime from src. If there are not enough bytes it |
| 371 | // will return false. |
| 372 | func ReadTime(src []byte) (time.Time, []byte, bool) { |
| 373 | dt, rem, ok := readi64(src) |
| 374 | return time.Unix(dt/1e3, dt%1e3*1e6), rem, ok |
| 375 | } |
| 376 | |
| 377 | // AppendNullElement will append a BSON null element using key to dst |
| 378 | // and return the extended buffer. |
| 379 | func AppendNullElement(dst []byte, key string) []byte { return AppendHeader(dst, bsontype.Null, key) } |
| 380 | |
| 381 | // AppendRegex will append pattern and options to dst and return the extended buffer. |
| 382 | func AppendRegex(dst []byte, pattern, options string) []byte { |
| 383 | return append(dst, pattern+string(0x00)+options+string(0x00)...) |
| 384 | } |
| 385 | |
| 386 | // AppendRegexElement will append a BSON regex element using key, pattern, and |
| 387 | // options to dst and return the extended buffer. |
| 388 | func AppendRegexElement(dst []byte, key, pattern, options string) []byte { |
| 389 | return AppendRegex(AppendHeader(dst, bsontype.Regex, key), pattern, options) |
| 390 | } |
| 391 | |
| 392 | // ReadRegex will read a pattern and options from src. If there are not enough bytes it |
| 393 | // will return false. |
| 394 | func ReadRegex(src []byte) (pattern, options string, rem []byte, ok bool) { |
| 395 | pattern, rem, ok = readcstring(src) |
| 396 | if !ok { |
| 397 | return "", "", src, false |
| 398 | } |
| 399 | options, rem, ok = readcstring(rem) |
| 400 | if !ok { |
| 401 | return "", "", src, false |
| 402 | } |
| 403 | return pattern, options, rem, true |
| 404 | } |
| 405 | |
| 406 | // AppendDBPointer will append ns and oid to dst and return the extended buffer. |
| 407 | func AppendDBPointer(dst []byte, ns string, oid primitive.ObjectID) []byte { |
| 408 | return append(appendstring(dst, ns), oid[:]...) |
| 409 | } |
| 410 | |
| 411 | // AppendDBPointerElement will append a BSON DBPointer element using key, ns, |
| 412 | // and oid to dst and return the extended buffer. |
| 413 | func AppendDBPointerElement(dst []byte, key, ns string, oid primitive.ObjectID) []byte { |
| 414 | return AppendDBPointer(AppendHeader(dst, bsontype.DBPointer, key), ns, oid) |
| 415 | } |
| 416 | |
| 417 | // ReadDBPointer will read a ns and oid from src. If there are not enough bytes it |
| 418 | // will return false. |
| 419 | func ReadDBPointer(src []byte) (ns string, oid primitive.ObjectID, rem []byte, ok bool) { |
| 420 | ns, rem, ok = readstring(src) |
| 421 | if !ok { |
| 422 | return "", primitive.ObjectID{}, src, false |
| 423 | } |
| 424 | oid, rem, ok = ReadObjectID(rem) |
| 425 | if !ok { |
| 426 | return "", primitive.ObjectID{}, src, false |
| 427 | } |
| 428 | return ns, oid, rem, true |
| 429 | } |
| 430 | |
| 431 | // AppendJavaScript will append js to dst and return the extended buffer. |
| 432 | func AppendJavaScript(dst []byte, js string) []byte { return appendstring(dst, js) } |
| 433 | |
| 434 | // AppendJavaScriptElement will append a BSON JavaScript element using key and |
| 435 | // js to dst and return the extended buffer. |
| 436 | func AppendJavaScriptElement(dst []byte, key, js string) []byte { |
| 437 | return AppendJavaScript(AppendHeader(dst, bsontype.JavaScript, key), js) |
| 438 | } |
| 439 | |
| 440 | // ReadJavaScript will read a js string from src. If there are not enough bytes it |
| 441 | // will return false. |
| 442 | func ReadJavaScript(src []byte) (js string, rem []byte, ok bool) { return readstring(src) } |
| 443 | |
| 444 | // AppendSymbol will append symbol to dst and return the extended buffer. |
| 445 | func AppendSymbol(dst []byte, symbol string) []byte { return appendstring(dst, symbol) } |
| 446 | |
| 447 | // AppendSymbolElement will append a BSON symbol element using key and symbol to dst |
| 448 | // and return the extended buffer. |
| 449 | func AppendSymbolElement(dst []byte, key, symbol string) []byte { |
| 450 | return AppendSymbol(AppendHeader(dst, bsontype.Symbol, key), symbol) |
| 451 | } |
| 452 | |
| 453 | // ReadSymbol will read a symbol string from src. If there are not enough bytes it |
| 454 | // will return false. |
| 455 | func ReadSymbol(src []byte) (symbol string, rem []byte, ok bool) { return readstring(src) } |
| 456 | |
| 457 | // AppendCodeWithScope will append code and scope to dst and return the extended buffer. |
| 458 | func AppendCodeWithScope(dst []byte, code string, scope []byte) []byte { |
| 459 | length := int32(4 + 4 + len(code) + 1 + len(scope)) // length of cws, length of code, code, 0x00, scope |
| 460 | dst = appendLength(dst, length) |
| 461 | |
| 462 | return append(appendstring(dst, code), scope...) |
| 463 | } |
| 464 | |
| 465 | // AppendCodeWithScopeElement will append a BSON code with scope element using |
| 466 | // key, code, and scope to dst |
| 467 | // and return the extended buffer. |
| 468 | func AppendCodeWithScopeElement(dst []byte, key, code string, scope []byte) []byte { |
| 469 | return AppendCodeWithScope(AppendHeader(dst, bsontype.CodeWithScope, key), code, scope) |
| 470 | } |
| 471 | |
| 472 | // ReadCodeWithScope will read code and scope from src. If there are not enough bytes it |
| 473 | // will return false. |
| 474 | func ReadCodeWithScope(src []byte) (code string, scope []byte, rem []byte, ok bool) { |
| 475 | length, rem, ok := ReadLength(src) |
| 476 | if !ok || len(src) < int(length) { |
| 477 | return "", nil, src, false |
| 478 | } |
| 479 | |
| 480 | code, rem, ok = readstring(rem) |
| 481 | if !ok { |
| 482 | return "", nil, src, false |
| 483 | } |
| 484 | |
| 485 | scope, rem, ok = ReadDocument(rem) |
| 486 | if !ok { |
| 487 | return "", nil, src, false |
| 488 | } |
| 489 | return code, scope, rem, true |
| 490 | } |
| 491 | |
| 492 | // AppendInt32 will append i32 to dst and return the extended buffer. |
| 493 | func AppendInt32(dst []byte, i32 int32) []byte { return appendi32(dst, i32) } |
| 494 | |
| 495 | // AppendInt32Element will append a BSON int32 element using key and i32 to dst |
| 496 | // and return the extended buffer. |
| 497 | func AppendInt32Element(dst []byte, key string, i32 int32) []byte { |
| 498 | return AppendInt32(AppendHeader(dst, bsontype.Int32, key), i32) |
| 499 | } |
| 500 | |
| 501 | // ReadInt32 will read an int32 from src. If there are not enough bytes it |
| 502 | // will return false. |
| 503 | func ReadInt32(src []byte) (int32, []byte, bool) { return readi32(src) } |
| 504 | |
| 505 | // AppendTimestamp will append t and i to dst and return the extended buffer. |
| 506 | func AppendTimestamp(dst []byte, t, i uint32) []byte { |
| 507 | return appendu32(appendu32(dst, i), t) // i is the lower 4 bytes, t is the higher 4 bytes |
| 508 | } |
| 509 | |
| 510 | // AppendTimestampElement will append a BSON timestamp element using key, t, and |
| 511 | // i to dst and return the extended buffer. |
| 512 | func AppendTimestampElement(dst []byte, key string, t, i uint32) []byte { |
| 513 | return AppendTimestamp(AppendHeader(dst, bsontype.Timestamp, key), t, i) |
| 514 | } |
| 515 | |
| 516 | // ReadTimestamp will read t and i from src. If there are not enough bytes it |
| 517 | // will return false. |
| 518 | func ReadTimestamp(src []byte) (t, i uint32, rem []byte, ok bool) { |
| 519 | i, rem, ok = readu32(src) |
| 520 | if !ok { |
| 521 | return 0, 0, src, false |
| 522 | } |
| 523 | t, rem, ok = readu32(rem) |
| 524 | if !ok { |
| 525 | return 0, 0, src, false |
| 526 | } |
| 527 | return t, i, rem, true |
| 528 | } |
| 529 | |
| 530 | // AppendInt64 will append i64 to dst and return the extended buffer. |
| 531 | func AppendInt64(dst []byte, i64 int64) []byte { return appendi64(dst, i64) } |
| 532 | |
| 533 | // AppendInt64Element will append a BSON int64 element using key and i64 to dst |
| 534 | // and return the extended buffer. |
| 535 | func AppendInt64Element(dst []byte, key string, i64 int64) []byte { |
| 536 | return AppendInt64(AppendHeader(dst, bsontype.Int64, key), i64) |
| 537 | } |
| 538 | |
| 539 | // ReadInt64 will read an int64 from src. If there are not enough bytes it |
| 540 | // will return false. |
| 541 | func ReadInt64(src []byte) (int64, []byte, bool) { return readi64(src) } |
| 542 | |
| 543 | // AppendDecimal128 will append d128 to dst and return the extended buffer. |
| 544 | func AppendDecimal128(dst []byte, d128 primitive.Decimal128) []byte { |
| 545 | high, low := d128.GetBytes() |
| 546 | return appendu64(appendu64(dst, low), high) |
| 547 | } |
| 548 | |
| 549 | // AppendDecimal128Element will append a BSON primitive.28 element using key and |
| 550 | // d128 to dst and return the extended buffer. |
| 551 | func AppendDecimal128Element(dst []byte, key string, d128 primitive.Decimal128) []byte { |
| 552 | return AppendDecimal128(AppendHeader(dst, bsontype.Decimal128, key), d128) |
| 553 | } |
| 554 | |
| 555 | // ReadDecimal128 will read a primitive.Decimal128 from src. If there are not enough bytes it |
| 556 | // will return false. |
| 557 | func ReadDecimal128(src []byte) (primitive.Decimal128, []byte, bool) { |
| 558 | l, rem, ok := readu64(src) |
| 559 | if !ok { |
| 560 | return primitive.Decimal128{}, src, false |
| 561 | } |
| 562 | |
| 563 | h, rem, ok := readu64(rem) |
| 564 | if !ok { |
| 565 | return primitive.Decimal128{}, src, false |
| 566 | } |
| 567 | |
| 568 | return primitive.NewDecimal128(h, l), rem, true |
| 569 | } |
| 570 | |
| 571 | // AppendMaxKeyElement will append a BSON max key element using key to dst |
| 572 | // and return the extended buffer. |
| 573 | func AppendMaxKeyElement(dst []byte, key string) []byte { |
| 574 | return AppendHeader(dst, bsontype.MaxKey, key) |
| 575 | } |
| 576 | |
| 577 | // AppendMinKeyElement will append a BSON min key element using key to dst |
| 578 | // and return the extended buffer. |
| 579 | func AppendMinKeyElement(dst []byte, key string) []byte { |
| 580 | return AppendHeader(dst, bsontype.MinKey, key) |
| 581 | } |
| 582 | |
| 583 | // EqualValue will return true if the two values are equal. |
| 584 | func EqualValue(t1, t2 bsontype.Type, v1, v2 []byte) bool { |
| 585 | if t1 != t2 { |
| 586 | return false |
| 587 | } |
| 588 | v1, _, ok := readValue(v1, t1) |
| 589 | if !ok { |
| 590 | return false |
| 591 | } |
| 592 | v2, _, ok = readValue(v2, t2) |
| 593 | if !ok { |
| 594 | return false |
| 595 | } |
| 596 | return bytes.Equal(v1, v2) |
| 597 | } |
| 598 | |
| 599 | // valueLength will determine the length of the next value contained in src as if it |
| 600 | // is type t. The returned bool will be false if there are not enough bytes in src for |
| 601 | // a value of type t. |
| 602 | func valueLength(src []byte, t bsontype.Type) (int32, bool) { |
| 603 | var length int32 |
| 604 | ok := true |
| 605 | switch t { |
| 606 | case bsontype.Array, bsontype.EmbeddedDocument, bsontype.CodeWithScope: |
| 607 | length, _, ok = ReadLength(src) |
| 608 | case bsontype.Binary: |
| 609 | length, _, ok = ReadLength(src) |
| 610 | length += 4 + 1 // binary length + subtype byte |
| 611 | case bsontype.Boolean: |
| 612 | length = 1 |
| 613 | case bsontype.DBPointer: |
| 614 | length, _, ok = ReadLength(src) |
| 615 | length += 4 + 12 // string length + ObjectID length |
| 616 | case bsontype.DateTime, bsontype.Double, bsontype.Int64, bsontype.Timestamp: |
| 617 | length = 8 |
| 618 | case bsontype.Decimal128: |
| 619 | length = 16 |
| 620 | case bsontype.Int32: |
| 621 | length = 4 |
| 622 | case bsontype.JavaScript, bsontype.String, bsontype.Symbol: |
| 623 | length, _, ok = ReadLength(src) |
| 624 | length += 4 |
| 625 | case bsontype.MaxKey, bsontype.MinKey, bsontype.Null, bsontype.Undefined: |
| 626 | length = 0 |
| 627 | case bsontype.ObjectID: |
| 628 | length = 12 |
| 629 | case bsontype.Regex: |
| 630 | regex := bytes.IndexByte(src, 0x00) |
| 631 | if regex < 0 { |
| 632 | ok = false |
| 633 | break |
| 634 | } |
| 635 | pattern := bytes.IndexByte(src[regex+1:], 0x00) |
| 636 | if pattern < 0 { |
| 637 | ok = false |
| 638 | break |
| 639 | } |
| 640 | length = int32(int64(regex) + 1 + int64(pattern) + 1) |
| 641 | default: |
| 642 | ok = false |
| 643 | } |
| 644 | |
| 645 | return length, ok |
| 646 | } |
| 647 | |
| 648 | func readValue(src []byte, t bsontype.Type) ([]byte, []byte, bool) { |
| 649 | length, ok := valueLength(src, t) |
| 650 | if !ok || int(length) > len(src) { |
| 651 | return nil, src, false |
| 652 | } |
| 653 | |
| 654 | return src[:length], src[length:], true |
| 655 | } |
| 656 | |
| 657 | // ReserveLength reserves the space required for length and returns the index where to write the length |
| 658 | // and the []byte with reserved space. |
| 659 | func ReserveLength(dst []byte) (int32, []byte) { |
| 660 | index := len(dst) |
| 661 | return int32(index), append(dst, 0x00, 0x00, 0x00, 0x00) |
| 662 | } |
| 663 | |
| 664 | // UpdateLength updates the length at index with length and returns the []byte. |
| 665 | func UpdateLength(dst []byte, index, length int32) []byte { |
| 666 | dst[index] = byte(length) |
| 667 | dst[index+1] = byte(length >> 8) |
| 668 | dst[index+2] = byte(length >> 16) |
| 669 | dst[index+3] = byte(length >> 24) |
| 670 | return dst |
| 671 | } |
| 672 | |
| 673 | func appendLength(dst []byte, l int32) []byte { return appendi32(dst, l) } |
| 674 | |
| 675 | func appendi32(dst []byte, i32 int32) []byte { |
| 676 | return append(dst, byte(i32), byte(i32>>8), byte(i32>>16), byte(i32>>24)) |
| 677 | } |
| 678 | |
| 679 | // ReadLength reads an int32 length from src and returns the length and the remaining bytes. If |
| 680 | // there aren't enough bytes to read a valid length, src is returned unomdified and the returned |
| 681 | // bool will be false. |
| 682 | func ReadLength(src []byte) (int32, []byte, bool) { return readi32(src) } |
| 683 | |
| 684 | func readi32(src []byte) (int32, []byte, bool) { |
| 685 | if len(src) < 4 { |
| 686 | return 0, src, false |
| 687 | } |
| 688 | |
| 689 | return (int32(src[0]) | int32(src[1])<<8 | int32(src[2])<<16 | int32(src[3])<<24), src[4:], true |
| 690 | } |
| 691 | |
| 692 | func appendi64(dst []byte, i64 int64) []byte { |
| 693 | return append(dst, |
| 694 | byte(i64), byte(i64>>8), byte(i64>>16), byte(i64>>24), |
| 695 | byte(i64>>32), byte(i64>>40), byte(i64>>48), byte(i64>>56), |
| 696 | ) |
| 697 | } |
| 698 | |
| 699 | func readi64(src []byte) (int64, []byte, bool) { |
| 700 | if len(src) < 8 { |
| 701 | return 0, src, false |
| 702 | } |
| 703 | i64 := (int64(src[0]) | int64(src[1])<<8 | int64(src[2])<<16 | int64(src[3])<<24 | |
| 704 | int64(src[4])<<32 | int64(src[5])<<40 | int64(src[6])<<48 | int64(src[7])<<56) |
| 705 | return i64, src[8:], true |
| 706 | } |
| 707 | |
| 708 | func appendu32(dst []byte, u32 uint32) []byte { |
| 709 | return append(dst, byte(u32), byte(u32>>8), byte(u32>>16), byte(u32>>24)) |
| 710 | } |
| 711 | |
| 712 | func readu32(src []byte) (uint32, []byte, bool) { |
| 713 | if len(src) < 4 { |
| 714 | return 0, src, false |
| 715 | } |
| 716 | |
| 717 | return (uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24), src[4:], true |
| 718 | } |
| 719 | |
| 720 | func appendu64(dst []byte, u64 uint64) []byte { |
| 721 | return append(dst, |
| 722 | byte(u64), byte(u64>>8), byte(u64>>16), byte(u64>>24), |
| 723 | byte(u64>>32), byte(u64>>40), byte(u64>>48), byte(u64>>56), |
| 724 | ) |
| 725 | } |
| 726 | |
| 727 | func readu64(src []byte) (uint64, []byte, bool) { |
| 728 | if len(src) < 8 { |
| 729 | return 0, src, false |
| 730 | } |
| 731 | u64 := (uint64(src[0]) | uint64(src[1])<<8 | uint64(src[2])<<16 | uint64(src[3])<<24 | |
| 732 | uint64(src[4])<<32 | uint64(src[5])<<40 | uint64(src[6])<<48 | uint64(src[7])<<56) |
| 733 | return u64, src[8:], true |
| 734 | } |
| 735 | |
| 736 | // keep in sync with readcstringbytes |
| 737 | func readcstring(src []byte) (string, []byte, bool) { |
| 738 | idx := bytes.IndexByte(src, 0x00) |
| 739 | if idx < 0 { |
| 740 | return "", src, false |
| 741 | } |
| 742 | return string(src[:idx]), src[idx+1:], true |
| 743 | } |
| 744 | |
| 745 | // keep in sync with readcstring |
| 746 | func readcstringbytes(src []byte) ([]byte, []byte, bool) { |
| 747 | idx := bytes.IndexByte(src, 0x00) |
| 748 | if idx < 0 { |
| 749 | return nil, src, false |
| 750 | } |
| 751 | return src[:idx], src[idx+1:], true |
| 752 | } |
| 753 | |
| 754 | func appendstring(dst []byte, s string) []byte { |
| 755 | l := int32(len(s) + 1) |
| 756 | dst = appendLength(dst, l) |
| 757 | dst = append(dst, s...) |
| 758 | return append(dst, 0x00) |
| 759 | } |
| 760 | |
| 761 | func readstring(src []byte) (string, []byte, bool) { |
| 762 | l, rem, ok := ReadLength(src) |
| 763 | if !ok { |
| 764 | return "", src, false |
| 765 | } |
| 766 | if len(src[4:]) < int(l) { |
| 767 | return "", src, false |
| 768 | } |
| 769 | |
| 770 | return string(rem[:l-1]), rem[l:], true |
| 771 | } |
| 772 | |
| 773 | // readLengthBytes attempts to read a length and that number of bytes. This |
| 774 | // function requires that the length include the four bytes for itself. |
| 775 | func readLengthBytes(src []byte) ([]byte, []byte, bool) { |
| 776 | l, _, ok := ReadLength(src) |
| 777 | if !ok { |
| 778 | return nil, src, false |
| 779 | } |
| 780 | if len(src) < int(l) { |
| 781 | return nil, src, false |
| 782 | } |
| 783 | return src[:l], src[l:], true |
| 784 | } |
| 785 | |
| 786 | func appendBinarySubtype2(dst []byte, subtype byte, b []byte) []byte { |
| 787 | dst = appendLength(dst, int32(len(b)+4)) // The bytes we'll encode need to be 4 larger for the length bytes |
| 788 | dst = append(dst, subtype) |
| 789 | dst = appendLength(dst, int32(len(b))) |
| 790 | return append(dst, b...) |
| 791 | } |