bson 6.2.0 → 6.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/bson.cjs CHANGED
@@ -97,8 +97,8 @@ class BSONError extends Error {
97
97
  get name() {
98
98
  return 'BSONError';
99
99
  }
100
- constructor(message) {
101
- super(message);
100
+ constructor(message, options) {
101
+ super(message, options);
102
102
  }
103
103
  static isBSONError(value) {
104
104
  return (value != null &&
@@ -127,6 +127,94 @@ class BSONRuntimeError extends BSONError {
127
127
  }
128
128
  }
129
129
 
130
+ const FIRST_BIT = 0x80;
131
+ const FIRST_TWO_BITS = 0xc0;
132
+ const FIRST_THREE_BITS = 0xe0;
133
+ const FIRST_FOUR_BITS = 0xf0;
134
+ const FIRST_FIVE_BITS = 0xf8;
135
+ const TWO_BIT_CHAR = 0xc0;
136
+ const THREE_BIT_CHAR = 0xe0;
137
+ const FOUR_BIT_CHAR = 0xf0;
138
+ const CONTINUING_CHAR = 0x80;
139
+ function validateUtf8(bytes, start, end) {
140
+ let continuation = 0;
141
+ for (let i = start; i < end; i += 1) {
142
+ const byte = bytes[i];
143
+ if (continuation) {
144
+ if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
145
+ return false;
146
+ }
147
+ continuation -= 1;
148
+ }
149
+ else if (byte & FIRST_BIT) {
150
+ if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
151
+ continuation = 1;
152
+ }
153
+ else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
154
+ continuation = 2;
155
+ }
156
+ else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
157
+ continuation = 3;
158
+ }
159
+ else {
160
+ return false;
161
+ }
162
+ }
163
+ }
164
+ return !continuation;
165
+ }
166
+
167
+ function tryReadBasicLatin(uint8array, start, end) {
168
+ if (uint8array.length === 0) {
169
+ return '';
170
+ }
171
+ const stringByteLength = end - start;
172
+ if (stringByteLength === 0) {
173
+ return '';
174
+ }
175
+ if (stringByteLength > 20) {
176
+ return null;
177
+ }
178
+ if (stringByteLength === 1 && uint8array[start] < 128) {
179
+ return String.fromCharCode(uint8array[start]);
180
+ }
181
+ if (stringByteLength === 2 && uint8array[start] < 128 && uint8array[start + 1] < 128) {
182
+ return String.fromCharCode(uint8array[start]) + String.fromCharCode(uint8array[start + 1]);
183
+ }
184
+ if (stringByteLength === 3 &&
185
+ uint8array[start] < 128 &&
186
+ uint8array[start + 1] < 128 &&
187
+ uint8array[start + 2] < 128) {
188
+ return (String.fromCharCode(uint8array[start]) +
189
+ String.fromCharCode(uint8array[start + 1]) +
190
+ String.fromCharCode(uint8array[start + 2]));
191
+ }
192
+ const latinBytes = [];
193
+ for (let i = start; i < end; i++) {
194
+ const byte = uint8array[i];
195
+ if (byte > 127) {
196
+ return null;
197
+ }
198
+ latinBytes.push(byte);
199
+ }
200
+ return String.fromCharCode(...latinBytes);
201
+ }
202
+ function tryWriteBasicLatin(destination, source, offset) {
203
+ if (source.length === 0)
204
+ return 0;
205
+ if (source.length > 25)
206
+ return null;
207
+ if (destination.length - offset < source.length)
208
+ return null;
209
+ for (let charOffset = 0, destinationOffset = offset; charOffset < source.length; charOffset++, destinationOffset++) {
210
+ const char = source.charCodeAt(charOffset);
211
+ if (char > 127)
212
+ return null;
213
+ destination[destinationOffset] = char;
214
+ }
215
+ return source.length;
216
+ }
217
+
130
218
  function nodejsMathRandomBytes(byteLength) {
131
219
  return nodeJsByteUtils.fromNumberArray(Array.from({ length: byteLength }, () => Math.floor(Math.random() * 256)));
132
220
  }
@@ -158,6 +246,9 @@ const nodeJsByteUtils = {
158
246
  allocate(size) {
159
247
  return Buffer.alloc(size);
160
248
  },
249
+ allocateUnsafe(size) {
250
+ return Buffer.allocUnsafe(size);
251
+ },
161
252
  equals(a, b) {
162
253
  return nodeJsByteUtils.toLocalBufferType(a).equals(b);
163
254
  },
@@ -182,16 +273,32 @@ const nodeJsByteUtils = {
182
273
  toHex(buffer) {
183
274
  return nodeJsByteUtils.toLocalBufferType(buffer).toString('hex');
184
275
  },
185
- fromUTF8(text) {
186
- return Buffer.from(text, 'utf8');
187
- },
188
- toUTF8(buffer, start, end) {
189
- return nodeJsByteUtils.toLocalBufferType(buffer).toString('utf8', start, end);
276
+ toUTF8(buffer, start, end, fatal) {
277
+ const basicLatin = end - start <= 20 ? tryReadBasicLatin(buffer, start, end) : null;
278
+ if (basicLatin != null) {
279
+ return basicLatin;
280
+ }
281
+ const string = nodeJsByteUtils.toLocalBufferType(buffer).toString('utf8', start, end);
282
+ if (fatal) {
283
+ for (let i = 0; i < string.length; i++) {
284
+ if (string.charCodeAt(i) === 0xfffd) {
285
+ if (!validateUtf8(buffer, start, end)) {
286
+ throw new BSONError('Invalid UTF-8 string in BSON document');
287
+ }
288
+ break;
289
+ }
290
+ }
291
+ }
292
+ return string;
190
293
  },
191
294
  utf8ByteLength(input) {
192
295
  return Buffer.byteLength(input, 'utf8');
193
296
  },
194
297
  encodeUTF8Into(buffer, source, byteOffset) {
298
+ const latinBytesWritten = tryWriteBasicLatin(buffer, source, byteOffset);
299
+ if (latinBytesWritten != null) {
300
+ return latinBytesWritten;
301
+ }
195
302
  return nodeJsByteUtils.toLocalBufferType(buffer).write(source, byteOffset, undefined, 'utf8');
196
303
  },
197
304
  randomBytes: nodejsRandomBytes
@@ -247,6 +354,9 @@ const webByteUtils = {
247
354
  }
248
355
  return new Uint8Array(size);
249
356
  },
357
+ allocateUnsafe(size) {
358
+ return webByteUtils.allocate(size);
359
+ },
250
360
  equals(a, b) {
251
361
  if (a.byteLength !== b.byteLength) {
252
362
  return false;
@@ -293,18 +403,27 @@ const webByteUtils = {
293
403
  toHex(uint8array) {
294
404
  return Array.from(uint8array, byte => byte.toString(16).padStart(2, '0')).join('');
295
405
  },
296
- fromUTF8(text) {
297
- return new TextEncoder().encode(text);
298
- },
299
- toUTF8(uint8array, start, end) {
300
- return new TextDecoder('utf8', { fatal: false }).decode(uint8array.slice(start, end));
406
+ toUTF8(uint8array, start, end, fatal) {
407
+ const basicLatin = end - start <= 20 ? tryReadBasicLatin(uint8array, start, end) : null;
408
+ if (basicLatin != null) {
409
+ return basicLatin;
410
+ }
411
+ if (fatal) {
412
+ try {
413
+ return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
414
+ }
415
+ catch (cause) {
416
+ throw new BSONError('Invalid UTF-8 string in BSON document', { cause });
417
+ }
418
+ }
419
+ return new TextDecoder('utf8', { fatal }).decode(uint8array.slice(start, end));
301
420
  },
302
421
  utf8ByteLength(input) {
303
- return webByteUtils.fromUTF8(input).byteLength;
422
+ return new TextEncoder().encode(input).byteLength;
304
423
  },
305
- encodeUTF8Into(buffer, source, byteOffset) {
306
- const bytes = webByteUtils.fromUTF8(source);
307
- buffer.set(bytes, byteOffset);
424
+ encodeUTF8Into(uint8array, source, byteOffset) {
425
+ const bytes = new TextEncoder().encode(source);
426
+ uint8array.set(bytes, byteOffset);
308
427
  return bytes.byteLength;
309
428
  },
310
429
  randomBytes: webRandomBytes
@@ -312,11 +431,6 @@ const webByteUtils = {
312
431
 
313
432
  const hasGlobalBuffer = typeof Buffer === 'function' && Buffer.prototype?._isBuffer !== true;
314
433
  const ByteUtils = hasGlobalBuffer ? nodeJsByteUtils : webByteUtils;
315
- class BSONDataView extends DataView {
316
- static fromUint8Array(input) {
317
- return new DataView(input.buffer, input.byteOffset, input.byteLength);
318
- }
319
- }
320
434
 
321
435
  class BSONValue {
322
436
  get [Symbol.for('@@mdb.bson.version')]() {
@@ -418,8 +532,8 @@ class Binary extends BSONValue {
418
532
  if (encoding === 'base64')
419
533
  return ByteUtils.toBase64(this.buffer);
420
534
  if (encoding === 'utf8' || encoding === 'utf-8')
421
- return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
422
- return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength);
535
+ return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength, false);
536
+ return ByteUtils.toUTF8(this.buffer, 0, this.buffer.byteLength, false);
423
537
  }
424
538
  toExtendedJSON(options) {
425
539
  options = options || {};
@@ -1736,7 +1850,7 @@ class Decimal128 extends BSONValue {
1736
1850
  if (isNegative) {
1737
1851
  dec.high = dec.high.or(Long.fromString('9223372036854775808'));
1738
1852
  }
1739
- const buffer = ByteUtils.allocate(16);
1853
+ const buffer = ByteUtils.allocateUnsafe(16);
1740
1854
  index = 0;
1741
1855
  buffer[index++] = dec.low.low & 0xff;
1742
1856
  buffer[index++] = (dec.low.low >> 8) & 0xff;
@@ -2009,9 +2123,99 @@ class MinKey extends BSONValue {
2009
2123
  }
2010
2124
  }
2011
2125
 
2126
+ const FLOAT = new Float64Array(1);
2127
+ const FLOAT_BYTES = new Uint8Array(FLOAT.buffer, 0, 8);
2128
+ const NumberUtils = {
2129
+ getInt32LE(source, offset) {
2130
+ return (source[offset] |
2131
+ (source[offset + 1] << 8) |
2132
+ (source[offset + 2] << 16) |
2133
+ (source[offset + 3] << 24));
2134
+ },
2135
+ getUint32LE(source, offset) {
2136
+ return (source[offset] +
2137
+ source[offset + 1] * 256 +
2138
+ source[offset + 2] * 65536 +
2139
+ source[offset + 3] * 16777216);
2140
+ },
2141
+ getUint32BE(source, offset) {
2142
+ return (source[offset + 3] +
2143
+ source[offset + 2] * 256 +
2144
+ source[offset + 1] * 65536 +
2145
+ source[offset] * 16777216);
2146
+ },
2147
+ getBigInt64LE(source, offset) {
2148
+ const lo = NumberUtils.getUint32LE(source, offset);
2149
+ const hi = NumberUtils.getUint32LE(source, offset + 4);
2150
+ return (BigInt(hi) << BigInt(32)) + BigInt(lo);
2151
+ },
2152
+ getFloat64LE(source, offset) {
2153
+ FLOAT_BYTES[0] = source[offset];
2154
+ FLOAT_BYTES[1] = source[offset + 1];
2155
+ FLOAT_BYTES[2] = source[offset + 2];
2156
+ FLOAT_BYTES[3] = source[offset + 3];
2157
+ FLOAT_BYTES[4] = source[offset + 4];
2158
+ FLOAT_BYTES[5] = source[offset + 5];
2159
+ FLOAT_BYTES[6] = source[offset + 6];
2160
+ FLOAT_BYTES[7] = source[offset + 7];
2161
+ return FLOAT[0];
2162
+ },
2163
+ setInt32BE(destination, offset, value) {
2164
+ destination[offset + 3] = value;
2165
+ value >>>= 8;
2166
+ destination[offset + 2] = value;
2167
+ value >>>= 8;
2168
+ destination[offset + 1] = value;
2169
+ value >>>= 8;
2170
+ destination[offset] = value;
2171
+ return 4;
2172
+ },
2173
+ setInt32LE(destination, offset, value) {
2174
+ destination[offset] = value;
2175
+ value >>>= 8;
2176
+ destination[offset + 1] = value;
2177
+ value >>>= 8;
2178
+ destination[offset + 2] = value;
2179
+ value >>>= 8;
2180
+ destination[offset + 3] = value;
2181
+ return 4;
2182
+ },
2183
+ setBigInt64LE(destination, offset, value) {
2184
+ const mask32bits = BigInt(4294967295);
2185
+ let lo = Number(value & mask32bits);
2186
+ destination[offset] = lo;
2187
+ lo >>= 8;
2188
+ destination[offset + 1] = lo;
2189
+ lo >>= 8;
2190
+ destination[offset + 2] = lo;
2191
+ lo >>= 8;
2192
+ destination[offset + 3] = lo;
2193
+ let hi = Number((value >> BigInt(32)) & mask32bits);
2194
+ destination[offset + 4] = hi;
2195
+ hi >>= 8;
2196
+ destination[offset + 5] = hi;
2197
+ hi >>= 8;
2198
+ destination[offset + 6] = hi;
2199
+ hi >>= 8;
2200
+ destination[offset + 7] = hi;
2201
+ return 8;
2202
+ },
2203
+ setFloat64LE(destination, offset, value) {
2204
+ FLOAT[0] = value;
2205
+ destination[offset] = FLOAT_BYTES[0];
2206
+ destination[offset + 1] = FLOAT_BYTES[1];
2207
+ destination[offset + 2] = FLOAT_BYTES[2];
2208
+ destination[offset + 3] = FLOAT_BYTES[3];
2209
+ destination[offset + 4] = FLOAT_BYTES[4];
2210
+ destination[offset + 5] = FLOAT_BYTES[5];
2211
+ destination[offset + 6] = FLOAT_BYTES[6];
2212
+ destination[offset + 7] = FLOAT_BYTES[7];
2213
+ return 8;
2214
+ }
2215
+ };
2216
+
2012
2217
  const checkForHexRegExp = new RegExp('^[0-9a-fA-F]{24}$');
2013
2218
  let PROCESS_UNIQUE = null;
2014
- const kId = Symbol('id');
2015
2219
  class ObjectId extends BSONValue {
2016
2220
  get _bsontype() {
2017
2221
  return 'ObjectId';
@@ -2034,14 +2238,14 @@ class ObjectId extends BSONValue {
2034
2238
  workingId = inputId;
2035
2239
  }
2036
2240
  if (workingId == null || typeof workingId === 'number') {
2037
- this[kId] = ObjectId.generate(typeof workingId === 'number' ? workingId : undefined);
2241
+ this.buffer = ObjectId.generate(typeof workingId === 'number' ? workingId : undefined);
2038
2242
  }
2039
2243
  else if (ArrayBuffer.isView(workingId) && workingId.byteLength === 12) {
2040
- this[kId] = ByteUtils.toLocalBufferType(workingId);
2244
+ this.buffer = ByteUtils.toLocalBufferType(workingId);
2041
2245
  }
2042
2246
  else if (typeof workingId === 'string') {
2043
2247
  if (workingId.length === 24 && checkForHexRegExp.test(workingId)) {
2044
- this[kId] = ByteUtils.fromHex(workingId);
2248
+ this.buffer = ByteUtils.fromHex(workingId);
2045
2249
  }
2046
2250
  else {
2047
2251
  throw new BSONError('input must be a 24 character hex string, 12 byte Uint8Array, or an integer');
@@ -2055,10 +2259,10 @@ class ObjectId extends BSONValue {
2055
2259
  }
2056
2260
  }
2057
2261
  get id() {
2058
- return this[kId];
2262
+ return this.buffer;
2059
2263
  }
2060
2264
  set id(value) {
2061
- this[kId] = value;
2265
+ this.buffer = value;
2062
2266
  if (ObjectId.cacheHexString) {
2063
2267
  this.__id = ByteUtils.toHex(value);
2064
2268
  }
@@ -2081,8 +2285,8 @@ class ObjectId extends BSONValue {
2081
2285
  time = Math.floor(Date.now() / 1000);
2082
2286
  }
2083
2287
  const inc = ObjectId.getInc();
2084
- const buffer = ByteUtils.allocate(12);
2085
- BSONDataView.fromUint8Array(buffer).setUint32(0, time, false);
2288
+ const buffer = ByteUtils.allocateUnsafe(12);
2289
+ NumberUtils.setInt32BE(buffer, 0, time);
2086
2290
  if (PROCESS_UNIQUE === null) {
2087
2291
  PROCESS_UNIQUE = ByteUtils.randomBytes(5);
2088
2292
  }
@@ -2117,7 +2321,7 @@ class ObjectId extends BSONValue {
2117
2321
  return false;
2118
2322
  }
2119
2323
  if (ObjectId.is(otherId)) {
2120
- return this[kId][11] === otherId[kId][11] && ByteUtils.equals(this[kId], otherId[kId]);
2324
+ return (this.buffer[11] === otherId.buffer[11] && ByteUtils.equals(this.buffer, otherId.buffer));
2121
2325
  }
2122
2326
  if (typeof otherId === 'string') {
2123
2327
  return otherId.toLowerCase() === this.toHexString();
@@ -2131,16 +2335,33 @@ class ObjectId extends BSONValue {
2131
2335
  }
2132
2336
  getTimestamp() {
2133
2337
  const timestamp = new Date();
2134
- const time = BSONDataView.fromUint8Array(this.id).getUint32(0, false);
2338
+ const time = NumberUtils.getUint32BE(this.buffer, 0);
2135
2339
  timestamp.setTime(Math.floor(time) * 1000);
2136
2340
  return timestamp;
2137
2341
  }
2138
2342
  static createPk() {
2139
2343
  return new ObjectId();
2140
2344
  }
2345
+ serializeInto(uint8array, index) {
2346
+ uint8array[index] = this.buffer[0];
2347
+ uint8array[index + 1] = this.buffer[1];
2348
+ uint8array[index + 2] = this.buffer[2];
2349
+ uint8array[index + 3] = this.buffer[3];
2350
+ uint8array[index + 4] = this.buffer[4];
2351
+ uint8array[index + 5] = this.buffer[5];
2352
+ uint8array[index + 6] = this.buffer[6];
2353
+ uint8array[index + 7] = this.buffer[7];
2354
+ uint8array[index + 8] = this.buffer[8];
2355
+ uint8array[index + 9] = this.buffer[9];
2356
+ uint8array[index + 10] = this.buffer[10];
2357
+ uint8array[index + 11] = this.buffer[11];
2358
+ return 12;
2359
+ }
2141
2360
  static createFromTime(time) {
2142
- const buffer = ByteUtils.fromNumberArray([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
2143
- BSONDataView.fromUint8Array(buffer).setUint32(0, time, false);
2361
+ const buffer = ByteUtils.allocate(12);
2362
+ for (let i = 11; i >= 4; i--)
2363
+ buffer[i] = 0;
2364
+ NumberUtils.setInt32BE(buffer, 0, time);
2144
2365
  return new ObjectId(buffer);
2145
2366
  }
2146
2367
  static createFromHexString(hexString) {
@@ -2507,52 +2728,12 @@ class Timestamp extends LongWithoutOverridesClass {
2507
2728
  }
2508
2729
  Timestamp.MAX_VALUE = Long.MAX_UNSIGNED_VALUE;
2509
2730
 
2510
- const FIRST_BIT = 0x80;
2511
- const FIRST_TWO_BITS = 0xc0;
2512
- const FIRST_THREE_BITS = 0xe0;
2513
- const FIRST_FOUR_BITS = 0xf0;
2514
- const FIRST_FIVE_BITS = 0xf8;
2515
- const TWO_BIT_CHAR = 0xc0;
2516
- const THREE_BIT_CHAR = 0xe0;
2517
- const FOUR_BIT_CHAR = 0xf0;
2518
- const CONTINUING_CHAR = 0x80;
2519
- function validateUtf8(bytes, start, end) {
2520
- let continuation = 0;
2521
- for (let i = start; i < end; i += 1) {
2522
- const byte = bytes[i];
2523
- if (continuation) {
2524
- if ((byte & FIRST_TWO_BITS) !== CONTINUING_CHAR) {
2525
- return false;
2526
- }
2527
- continuation -= 1;
2528
- }
2529
- else if (byte & FIRST_BIT) {
2530
- if ((byte & FIRST_THREE_BITS) === TWO_BIT_CHAR) {
2531
- continuation = 1;
2532
- }
2533
- else if ((byte & FIRST_FOUR_BITS) === THREE_BIT_CHAR) {
2534
- continuation = 2;
2535
- }
2536
- else if ((byte & FIRST_FIVE_BITS) === FOUR_BIT_CHAR) {
2537
- continuation = 3;
2538
- }
2539
- else {
2540
- return false;
2541
- }
2542
- }
2543
- }
2544
- return !continuation;
2545
- }
2546
-
2547
2731
  const JS_INT_MAX_LONG = Long.fromNumber(JS_INT_MAX);
2548
2732
  const JS_INT_MIN_LONG = Long.fromNumber(JS_INT_MIN);
2549
2733
  function internalDeserialize(buffer, options, isArray) {
2550
2734
  options = options == null ? {} : options;
2551
2735
  const index = options && options.index ? options.index : 0;
2552
- const size = buffer[index] |
2553
- (buffer[index + 1] << 8) |
2554
- (buffer[index + 2] << 16) |
2555
- (buffer[index + 3] << 24);
2736
+ const size = NumberUtils.getInt32LE(buffer, index);
2556
2737
  if (size < 5) {
2557
2738
  throw new BSONError(`bson size must be >= 5, is ${size}`);
2558
2739
  }
@@ -2588,7 +2769,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2588
2769
  const validation = options.validation == null ? { utf8: true } : options.validation;
2589
2770
  let globalUTFValidation = true;
2590
2771
  let validationSetting;
2591
- const utf8KeysSet = new Set();
2772
+ let utf8KeysSet;
2592
2773
  const utf8ValidatedKeys = validation.utf8;
2593
2774
  if (typeof utf8ValidatedKeys === 'boolean') {
2594
2775
  validationSetting = utf8ValidatedKeys;
@@ -2610,6 +2791,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2610
2791
  }
2611
2792
  }
2612
2793
  if (!globalUTFValidation) {
2794
+ utf8KeysSet = new Set();
2613
2795
  for (const key of Object.keys(utf8ValidatedKeys)) {
2614
2796
  utf8KeysSet.add(key);
2615
2797
  }
@@ -2617,14 +2799,14 @@ function deserializeObject(buffer, index, options, isArray = false) {
2617
2799
  const startIndex = index;
2618
2800
  if (buffer.length < 5)
2619
2801
  throw new BSONError('corrupt bson message < 5 bytes long');
2620
- const size = buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
2802
+ const size = NumberUtils.getInt32LE(buffer, index);
2803
+ index += 4;
2621
2804
  if (size < 5 || size > buffer.length)
2622
2805
  throw new BSONError('corrupt bson message');
2623
2806
  const object = isArray ? [] : {};
2624
2807
  let arrayIndex = 0;
2625
2808
  const done = false;
2626
2809
  let isPossibleDBRef = isArray ? false : null;
2627
- const dataview = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
2628
2810
  while (!done) {
2629
2811
  const elementType = buffer[index++];
2630
2812
  if (elementType === 0)
@@ -2635,9 +2817,9 @@ function deserializeObject(buffer, index, options, isArray = false) {
2635
2817
  }
2636
2818
  if (i >= buffer.byteLength)
2637
2819
  throw new BSONError('Bad BSON Document: illegal CString');
2638
- const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i);
2820
+ const name = isArray ? arrayIndex++ : ByteUtils.toUTF8(buffer, index, i, false);
2639
2821
  let shouldValidateKey = true;
2640
- if (globalUTFValidation || utf8KeysSet.has(name)) {
2822
+ if (globalUTFValidation || utf8KeysSet?.has(name)) {
2641
2823
  shouldValidateKey = validationSetting;
2642
2824
  }
2643
2825
  else {
@@ -2649,51 +2831,41 @@ function deserializeObject(buffer, index, options, isArray = false) {
2649
2831
  let value;
2650
2832
  index = i + 1;
2651
2833
  if (elementType === BSON_DATA_STRING) {
2652
- const stringSize = buffer[index++] |
2653
- (buffer[index++] << 8) |
2654
- (buffer[index++] << 16) |
2655
- (buffer[index++] << 24);
2834
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
2835
+ index += 4;
2656
2836
  if (stringSize <= 0 ||
2657
2837
  stringSize > buffer.length - index ||
2658
2838
  buffer[index + stringSize - 1] !== 0) {
2659
2839
  throw new BSONError('bad string length in bson');
2660
2840
  }
2661
- value = getValidatedString(buffer, index, index + stringSize - 1, shouldValidateKey);
2841
+ value = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
2662
2842
  index = index + stringSize;
2663
2843
  }
2664
2844
  else if (elementType === BSON_DATA_OID) {
2665
- const oid = ByteUtils.allocate(12);
2666
- oid.set(buffer.subarray(index, index + 12));
2845
+ const oid = ByteUtils.allocateUnsafe(12);
2846
+ for (let i = 0; i < 12; i++)
2847
+ oid[i] = buffer[index + i];
2667
2848
  value = new ObjectId(oid);
2668
2849
  index = index + 12;
2669
2850
  }
2670
2851
  else if (elementType === BSON_DATA_INT && promoteValues === false) {
2671
- value = new Int32(buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24));
2852
+ value = new Int32(NumberUtils.getInt32LE(buffer, index));
2853
+ index += 4;
2672
2854
  }
2673
2855
  else if (elementType === BSON_DATA_INT) {
2674
- value =
2675
- buffer[index++] |
2676
- (buffer[index++] << 8) |
2677
- (buffer[index++] << 16) |
2678
- (buffer[index++] << 24);
2679
- }
2680
- else if (elementType === BSON_DATA_NUMBER && promoteValues === false) {
2681
- value = new Double(dataview.getFloat64(index, true));
2682
- index = index + 8;
2856
+ value = NumberUtils.getInt32LE(buffer, index);
2857
+ index += 4;
2683
2858
  }
2684
2859
  else if (elementType === BSON_DATA_NUMBER) {
2685
- value = dataview.getFloat64(index, true);
2686
- index = index + 8;
2860
+ value = NumberUtils.getFloat64LE(buffer, index);
2861
+ index += 8;
2862
+ if (promoteValues === false)
2863
+ value = new Double(value);
2687
2864
  }
2688
2865
  else if (elementType === BSON_DATA_DATE) {
2689
- const lowBits = buffer[index++] |
2690
- (buffer[index++] << 8) |
2691
- (buffer[index++] << 16) |
2692
- (buffer[index++] << 24);
2693
- const highBits = buffer[index++] |
2694
- (buffer[index++] << 8) |
2695
- (buffer[index++] << 16) |
2696
- (buffer[index++] << 24);
2866
+ const lowBits = NumberUtils.getInt32LE(buffer, index);
2867
+ const highBits = NumberUtils.getInt32LE(buffer, index + 4);
2868
+ index += 8;
2697
2869
  value = new Date(new Long(lowBits, highBits).toNumber());
2698
2870
  }
2699
2871
  else if (elementType === BSON_DATA_BOOLEAN) {
@@ -2703,10 +2875,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2703
2875
  }
2704
2876
  else if (elementType === BSON_DATA_OBJECT) {
2705
2877
  const _index = index;
2706
- const objectSize = buffer[index] |
2707
- (buffer[index + 1] << 8) |
2708
- (buffer[index + 2] << 16) |
2709
- (buffer[index + 3] << 24);
2878
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
2710
2879
  if (objectSize <= 0 || objectSize > buffer.length - index)
2711
2880
  throw new BSONError('bad embedded document length in bson');
2712
2881
  if (raw) {
@@ -2723,10 +2892,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2723
2892
  }
2724
2893
  else if (elementType === BSON_DATA_ARRAY) {
2725
2894
  const _index = index;
2726
- const objectSize = buffer[index] |
2727
- (buffer[index + 1] << 8) |
2728
- (buffer[index + 2] << 16) |
2729
- (buffer[index + 3] << 24);
2895
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
2730
2896
  let arrayOptions = options;
2731
2897
  const stopIndex = index + objectSize;
2732
2898
  if (fieldsAsRaw && fieldsAsRaw[name]) {
@@ -2749,40 +2915,36 @@ function deserializeObject(buffer, index, options, isArray = false) {
2749
2915
  value = null;
2750
2916
  }
2751
2917
  else if (elementType === BSON_DATA_LONG) {
2752
- const dataview = BSONDataView.fromUint8Array(buffer.subarray(index, index + 8));
2753
- const lowBits = buffer[index++] |
2754
- (buffer[index++] << 8) |
2755
- (buffer[index++] << 16) |
2756
- (buffer[index++] << 24);
2757
- const highBits = buffer[index++] |
2758
- (buffer[index++] << 8) |
2759
- (buffer[index++] << 16) |
2760
- (buffer[index++] << 24);
2761
- const long = new Long(lowBits, highBits);
2762
2918
  if (useBigInt64) {
2763
- value = dataview.getBigInt64(0, true);
2764
- }
2765
- else if (promoteLongs && promoteValues === true) {
2766
- value =
2767
- long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
2768
- ? long.toNumber()
2769
- : long;
2919
+ value = NumberUtils.getBigInt64LE(buffer, index);
2920
+ index += 8;
2770
2921
  }
2771
2922
  else {
2772
- value = long;
2923
+ const lowBits = NumberUtils.getInt32LE(buffer, index);
2924
+ const highBits = NumberUtils.getInt32LE(buffer, index + 4);
2925
+ index += 8;
2926
+ const long = new Long(lowBits, highBits);
2927
+ if (promoteLongs && promoteValues === true) {
2928
+ value =
2929
+ long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
2930
+ ? long.toNumber()
2931
+ : long;
2932
+ }
2933
+ else {
2934
+ value = long;
2935
+ }
2773
2936
  }
2774
2937
  }
2775
2938
  else if (elementType === BSON_DATA_DECIMAL128) {
2776
- const bytes = ByteUtils.allocate(16);
2777
- bytes.set(buffer.subarray(index, index + 16), 0);
2939
+ const bytes = ByteUtils.allocateUnsafe(16);
2940
+ for (let i = 0; i < 16; i++)
2941
+ bytes[i] = buffer[index + i];
2778
2942
  index = index + 16;
2779
2943
  value = new Decimal128(bytes);
2780
2944
  }
2781
2945
  else if (elementType === BSON_DATA_BINARY) {
2782
- let binarySize = buffer[index++] |
2783
- (buffer[index++] << 8) |
2784
- (buffer[index++] << 16) |
2785
- (buffer[index++] << 24);
2946
+ let binarySize = NumberUtils.getInt32LE(buffer, index);
2947
+ index += 4;
2786
2948
  const totalBinarySize = binarySize;
2787
2949
  const subType = buffer[index++];
2788
2950
  if (binarySize < 0)
@@ -2791,11 +2953,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
2791
2953
  throw new BSONError('Binary type size larger than document size');
2792
2954
  if (buffer['slice'] != null) {
2793
2955
  if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
2794
- binarySize =
2795
- buffer[index++] |
2796
- (buffer[index++] << 8) |
2797
- (buffer[index++] << 16) |
2798
- (buffer[index++] << 24);
2956
+ binarySize = NumberUtils.getInt32LE(buffer, index);
2957
+ index += 4;
2799
2958
  if (binarySize < 0)
2800
2959
  throw new BSONError('Negative binary type element size found for subtype 0x02');
2801
2960
  if (binarySize > totalBinarySize - 4)
@@ -2814,13 +2973,9 @@ function deserializeObject(buffer, index, options, isArray = false) {
2814
2973
  }
2815
2974
  }
2816
2975
  else {
2817
- const _buffer = ByteUtils.allocate(binarySize);
2818
2976
  if (subType === Binary.SUBTYPE_BYTE_ARRAY) {
2819
- binarySize =
2820
- buffer[index++] |
2821
- (buffer[index++] << 8) |
2822
- (buffer[index++] << 16) |
2823
- (buffer[index++] << 24);
2977
+ binarySize = NumberUtils.getInt32LE(buffer, index);
2978
+ index += 4;
2824
2979
  if (binarySize < 0)
2825
2980
  throw new BSONError('Negative binary type element size found for subtype 0x02');
2826
2981
  if (binarySize > totalBinarySize - 4)
@@ -2828,11 +2983,11 @@ function deserializeObject(buffer, index, options, isArray = false) {
2828
2983
  if (binarySize < totalBinarySize - 4)
2829
2984
  throw new BSONError('Binary type with subtype 0x02 contains too short binary size');
2830
2985
  }
2831
- for (i = 0; i < binarySize; i++) {
2832
- _buffer[i] = buffer[index + i];
2833
- }
2834
2986
  if (promoteBuffers && promoteValues) {
2835
- value = _buffer;
2987
+ value = ByteUtils.allocateUnsafe(binarySize);
2988
+ for (i = 0; i < binarySize; i++) {
2989
+ value[i] = buffer[index + i];
2990
+ }
2836
2991
  }
2837
2992
  else {
2838
2993
  value = new Binary(buffer.slice(index, index + binarySize), subType);
@@ -2850,7 +3005,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2850
3005
  }
2851
3006
  if (i >= buffer.length)
2852
3007
  throw new BSONError('Bad BSON Document: illegal CString');
2853
- const source = ByteUtils.toUTF8(buffer, index, i);
3008
+ const source = ByteUtils.toUTF8(buffer, index, i, false);
2854
3009
  index = i + 1;
2855
3010
  i = index;
2856
3011
  while (buffer[i] !== 0x00 && i < buffer.length) {
@@ -2858,7 +3013,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2858
3013
  }
2859
3014
  if (i >= buffer.length)
2860
3015
  throw new BSONError('Bad BSON Document: illegal CString');
2861
- const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
3016
+ const regExpOptions = ByteUtils.toUTF8(buffer, index, i, false);
2862
3017
  index = i + 1;
2863
3018
  const optionsArray = new Array(regExpOptions.length);
2864
3019
  for (i = 0; i < regExpOptions.length; i++) {
@@ -2883,7 +3038,7 @@ function deserializeObject(buffer, index, options, isArray = false) {
2883
3038
  }
2884
3039
  if (i >= buffer.length)
2885
3040
  throw new BSONError('Bad BSON Document: illegal CString');
2886
- const source = ByteUtils.toUTF8(buffer, index, i);
3041
+ const source = ByteUtils.toUTF8(buffer, index, i, false);
2887
3042
  index = i + 1;
2888
3043
  i = index;
2889
3044
  while (buffer[i] !== 0x00 && i < buffer.length) {
@@ -2891,34 +3046,28 @@ function deserializeObject(buffer, index, options, isArray = false) {
2891
3046
  }
2892
3047
  if (i >= buffer.length)
2893
3048
  throw new BSONError('Bad BSON Document: illegal CString');
2894
- const regExpOptions = ByteUtils.toUTF8(buffer, index, i);
3049
+ const regExpOptions = ByteUtils.toUTF8(buffer, index, i, false);
2895
3050
  index = i + 1;
2896
3051
  value = new BSONRegExp(source, regExpOptions);
2897
3052
  }
2898
3053
  else if (elementType === BSON_DATA_SYMBOL) {
2899
- const stringSize = buffer[index++] |
2900
- (buffer[index++] << 8) |
2901
- (buffer[index++] << 16) |
2902
- (buffer[index++] << 24);
3054
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3055
+ index += 4;
2903
3056
  if (stringSize <= 0 ||
2904
3057
  stringSize > buffer.length - index ||
2905
3058
  buffer[index + stringSize - 1] !== 0) {
2906
3059
  throw new BSONError('bad string length in bson');
2907
3060
  }
2908
- const symbol = getValidatedString(buffer, index, index + stringSize - 1, shouldValidateKey);
3061
+ const symbol = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
2909
3062
  value = promoteValues ? symbol : new BSONSymbol(symbol);
2910
3063
  index = index + stringSize;
2911
3064
  }
2912
3065
  else if (elementType === BSON_DATA_TIMESTAMP) {
2913
- const i = buffer[index++] +
2914
- buffer[index++] * (1 << 8) +
2915
- buffer[index++] * (1 << 16) +
2916
- buffer[index++] * (1 << 24);
2917
- const t = buffer[index++] +
2918
- buffer[index++] * (1 << 8) +
2919
- buffer[index++] * (1 << 16) +
2920
- buffer[index++] * (1 << 24);
2921
- value = new Timestamp({ i, t });
3066
+ value = new Timestamp({
3067
+ i: NumberUtils.getUint32LE(buffer, index),
3068
+ t: NumberUtils.getUint32LE(buffer, index + 4)
3069
+ });
3070
+ index += 8;
2922
3071
  }
2923
3072
  else if (elementType === BSON_DATA_MIN_KEY) {
2924
3073
  value = new MinKey();
@@ -2927,43 +3076,34 @@ function deserializeObject(buffer, index, options, isArray = false) {
2927
3076
  value = new MaxKey();
2928
3077
  }
2929
3078
  else if (elementType === BSON_DATA_CODE) {
2930
- const stringSize = buffer[index++] |
2931
- (buffer[index++] << 8) |
2932
- (buffer[index++] << 16) |
2933
- (buffer[index++] << 24);
3079
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3080
+ index += 4;
2934
3081
  if (stringSize <= 0 ||
2935
3082
  stringSize > buffer.length - index ||
2936
3083
  buffer[index + stringSize - 1] !== 0) {
2937
3084
  throw new BSONError('bad string length in bson');
2938
3085
  }
2939
- const functionString = getValidatedString(buffer, index, index + stringSize - 1, shouldValidateKey);
3086
+ const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
2940
3087
  value = new Code(functionString);
2941
3088
  index = index + stringSize;
2942
3089
  }
2943
3090
  else if (elementType === BSON_DATA_CODE_W_SCOPE) {
2944
- const totalSize = buffer[index++] |
2945
- (buffer[index++] << 8) |
2946
- (buffer[index++] << 16) |
2947
- (buffer[index++] << 24);
3091
+ const totalSize = NumberUtils.getInt32LE(buffer, index);
3092
+ index += 4;
2948
3093
  if (totalSize < 4 + 4 + 4 + 1) {
2949
3094
  throw new BSONError('code_w_scope total size shorter minimum expected length');
2950
3095
  }
2951
- const stringSize = buffer[index++] |
2952
- (buffer[index++] << 8) |
2953
- (buffer[index++] << 16) |
2954
- (buffer[index++] << 24);
3096
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3097
+ index += 4;
2955
3098
  if (stringSize <= 0 ||
2956
3099
  stringSize > buffer.length - index ||
2957
3100
  buffer[index + stringSize - 1] !== 0) {
2958
3101
  throw new BSONError('bad string length in bson');
2959
3102
  }
2960
- const functionString = getValidatedString(buffer, index, index + stringSize - 1, shouldValidateKey);
3103
+ const functionString = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, shouldValidateKey);
2961
3104
  index = index + stringSize;
2962
3105
  const _index = index;
2963
- const objectSize = buffer[index] |
2964
- (buffer[index + 1] << 8) |
2965
- (buffer[index + 2] << 16) |
2966
- (buffer[index + 3] << 24);
3106
+ const objectSize = NumberUtils.getInt32LE(buffer, index);
2967
3107
  const scopeObject = deserializeObject(buffer, _index, options, false);
2968
3108
  index = index + objectSize;
2969
3109
  if (totalSize < 4 + 4 + objectSize + stringSize) {
@@ -2975,10 +3115,8 @@ function deserializeObject(buffer, index, options, isArray = false) {
2975
3115
  value = new Code(functionString, scopeObject);
2976
3116
  }
2977
3117
  else if (elementType === BSON_DATA_DBPOINTER) {
2978
- const stringSize = buffer[index++] |
2979
- (buffer[index++] << 8) |
2980
- (buffer[index++] << 16) |
2981
- (buffer[index++] << 24);
3118
+ const stringSize = NumberUtils.getInt32LE(buffer, index);
3119
+ index += 4;
2982
3120
  if (stringSize <= 0 ||
2983
3121
  stringSize > buffer.length - index ||
2984
3122
  buffer[index + stringSize - 1] !== 0)
@@ -2988,10 +3126,11 @@ function deserializeObject(buffer, index, options, isArray = false) {
2988
3126
  throw new BSONError('Invalid UTF-8 string in BSON document');
2989
3127
  }
2990
3128
  }
2991
- const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1);
3129
+ const namespace = ByteUtils.toUTF8(buffer, index, index + stringSize - 1, false);
2992
3130
  index = index + stringSize;
2993
- const oidBuffer = ByteUtils.allocate(12);
2994
- oidBuffer.set(buffer.subarray(index, index + 12), 0);
3131
+ const oidBuffer = ByteUtils.allocateUnsafe(12);
3132
+ for (let i = 0; i < 12; i++)
3133
+ oidBuffer[i] = buffer[index + i];
2995
3134
  const oid = new ObjectId(oidBuffer);
2996
3135
  index = index + 12;
2997
3136
  value = new DBRef(namespace, oid);
@@ -3027,20 +3166,6 @@ function deserializeObject(buffer, index, options, isArray = false) {
3027
3166
  }
3028
3167
  return object;
3029
3168
  }
3030
- function getValidatedString(buffer, start, end, shouldValidateUtf8) {
3031
- const value = ByteUtils.toUTF8(buffer, start, end);
3032
- if (shouldValidateUtf8) {
3033
- for (let i = 0; i < value.length; i++) {
3034
- if (value.charCodeAt(i) === 0xfffd) {
3035
- if (!validateUtf8(buffer, start, end)) {
3036
- throw new BSONError('Invalid UTF-8 string in BSON document');
3037
- }
3038
- break;
3039
- }
3040
- }
3041
- }
3042
- return value;
3043
- }
3044
3169
 
3045
3170
  const regexp = /\x00/;
3046
3171
  const ignoreKeys = new Set(['$db', '$ref', '$id', '$clusterTime']);
@@ -3050,17 +3175,11 @@ function serializeString(buffer, key, value, index) {
3050
3175
  index = index + numberOfWrittenBytes + 1;
3051
3176
  buffer[index - 1] = 0;
3052
3177
  const size = ByteUtils.encodeUTF8Into(buffer, value, index + 4);
3053
- buffer[index + 3] = ((size + 1) >> 24) & 0xff;
3054
- buffer[index + 2] = ((size + 1) >> 16) & 0xff;
3055
- buffer[index + 1] = ((size + 1) >> 8) & 0xff;
3056
- buffer[index] = (size + 1) & 0xff;
3178
+ NumberUtils.setInt32LE(buffer, index, size + 1);
3057
3179
  index = index + 4 + size;
3058
3180
  buffer[index++] = 0;
3059
3181
  return index;
3060
3182
  }
3061
- const NUMBER_SPACE = new DataView(new ArrayBuffer(8), 0, 8);
3062
- const FOUR_BYTE_VIEW_ON_NUMBER = new Uint8Array(NUMBER_SPACE.buffer, 0, 4);
3063
- const EIGHT_BYTE_VIEW_ON_NUMBER = new Uint8Array(NUMBER_SPACE.buffer, 0, 8);
3064
3183
  function serializeNumber(buffer, key, value, index) {
3065
3184
  const isNegativeZero = Object.is(value, -0);
3066
3185
  const type = !isNegativeZero &&
@@ -3069,19 +3188,16 @@ function serializeNumber(buffer, key, value, index) {
3069
3188
  value >= BSON_INT32_MIN
3070
3189
  ? BSON_DATA_INT
3071
3190
  : BSON_DATA_NUMBER;
3072
- if (type === BSON_DATA_INT) {
3073
- NUMBER_SPACE.setInt32(0, value, true);
3074
- }
3075
- else {
3076
- NUMBER_SPACE.setFloat64(0, value, true);
3077
- }
3078
- const bytes = type === BSON_DATA_INT ? FOUR_BYTE_VIEW_ON_NUMBER : EIGHT_BYTE_VIEW_ON_NUMBER;
3079
3191
  buffer[index++] = type;
3080
3192
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3081
3193
  index = index + numberOfWrittenBytes;
3082
3194
  buffer[index++] = 0x00;
3083
- buffer.set(bytes, index);
3084
- index += bytes.byteLength;
3195
+ if (type === BSON_DATA_INT) {
3196
+ index += NumberUtils.setInt32LE(buffer, index, value);
3197
+ }
3198
+ else {
3199
+ index += NumberUtils.setFloat64LE(buffer, index, value);
3200
+ }
3085
3201
  return index;
3086
3202
  }
3087
3203
  function serializeBigInt(buffer, key, value, index) {
@@ -3089,9 +3205,7 @@ function serializeBigInt(buffer, key, value, index) {
3089
3205
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3090
3206
  index += numberOfWrittenBytes;
3091
3207
  buffer[index++] = 0;
3092
- NUMBER_SPACE.setBigInt64(0, value, true);
3093
- buffer.set(EIGHT_BYTE_VIEW_ON_NUMBER, index);
3094
- index += EIGHT_BYTE_VIEW_ON_NUMBER.byteLength;
3208
+ index += NumberUtils.setBigInt64LE(buffer, index, value);
3095
3209
  return index;
3096
3210
  }
3097
3211
  function serializeNull(buffer, key, _, index) {
@@ -3117,14 +3231,8 @@ function serializeDate(buffer, key, value, index) {
3117
3231
  const dateInMilis = Long.fromNumber(value.getTime());
3118
3232
  const lowBits = dateInMilis.getLowBits();
3119
3233
  const highBits = dateInMilis.getHighBits();
3120
- buffer[index++] = lowBits & 0xff;
3121
- buffer[index++] = (lowBits >> 8) & 0xff;
3122
- buffer[index++] = (lowBits >> 16) & 0xff;
3123
- buffer[index++] = (lowBits >> 24) & 0xff;
3124
- buffer[index++] = highBits & 0xff;
3125
- buffer[index++] = (highBits >> 8) & 0xff;
3126
- buffer[index++] = (highBits >> 16) & 0xff;
3127
- buffer[index++] = (highBits >> 24) & 0xff;
3234
+ index += NumberUtils.setInt32LE(buffer, index, lowBits);
3235
+ index += NumberUtils.setInt32LE(buffer, index, highBits);
3128
3236
  return index;
3129
3237
  }
3130
3238
  function serializeRegExp(buffer, key, value, index) {
@@ -3181,15 +3289,7 @@ function serializeObjectId(buffer, key, value, index) {
3181
3289
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3182
3290
  index = index + numberOfWrittenBytes;
3183
3291
  buffer[index++] = 0;
3184
- const idValue = value.id;
3185
- if (isUint8Array(idValue)) {
3186
- for (let i = 0; i < 12; i++) {
3187
- buffer[index++] = idValue[i];
3188
- }
3189
- }
3190
- else {
3191
- throw new BSONError('object [' + JSON.stringify(value) + '] is not a valid ObjectId');
3192
- }
3292
+ index += value.serializeInto(buffer, index);
3193
3293
  return index;
3194
3294
  }
3195
3295
  function serializeBuffer(buffer, key, value, index) {
@@ -3198,12 +3298,15 @@ function serializeBuffer(buffer, key, value, index) {
3198
3298
  index = index + numberOfWrittenBytes;
3199
3299
  buffer[index++] = 0;
3200
3300
  const size = value.length;
3201
- buffer[index++] = size & 0xff;
3202
- buffer[index++] = (size >> 8) & 0xff;
3203
- buffer[index++] = (size >> 16) & 0xff;
3204
- buffer[index++] = (size >> 24) & 0xff;
3301
+ index += NumberUtils.setInt32LE(buffer, index, size);
3205
3302
  buffer[index++] = BSON_BINARY_SUBTYPE_DEFAULT;
3206
- buffer.set(value, index);
3303
+ if (size <= 16) {
3304
+ for (let i = 0; i < size; i++)
3305
+ buffer[index + i] = value[i];
3306
+ }
3307
+ else {
3308
+ buffer.set(value, index);
3309
+ }
3207
3310
  index = index + size;
3208
3311
  return index;
3209
3312
  }
@@ -3225,7 +3328,8 @@ function serializeDecimal128(buffer, key, value, index) {
3225
3328
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3226
3329
  index = index + numberOfWrittenBytes;
3227
3330
  buffer[index++] = 0;
3228
- buffer.set(value.bytes.subarray(0, 16), index);
3331
+ for (let i = 0; i < 16; i++)
3332
+ buffer[index + i] = value.bytes[i];
3229
3333
  return index + 16;
3230
3334
  }
3231
3335
  function serializeLong(buffer, key, value, index) {
@@ -3236,14 +3340,8 @@ function serializeLong(buffer, key, value, index) {
3236
3340
  buffer[index++] = 0;
3237
3341
  const lowBits = value.getLowBits();
3238
3342
  const highBits = value.getHighBits();
3239
- buffer[index++] = lowBits & 0xff;
3240
- buffer[index++] = (lowBits >> 8) & 0xff;
3241
- buffer[index++] = (lowBits >> 16) & 0xff;
3242
- buffer[index++] = (lowBits >> 24) & 0xff;
3243
- buffer[index++] = highBits & 0xff;
3244
- buffer[index++] = (highBits >> 8) & 0xff;
3245
- buffer[index++] = (highBits >> 16) & 0xff;
3246
- buffer[index++] = (highBits >> 24) & 0xff;
3343
+ index += NumberUtils.setInt32LE(buffer, index, lowBits);
3344
+ index += NumberUtils.setInt32LE(buffer, index, highBits);
3247
3345
  return index;
3248
3346
  }
3249
3347
  function serializeInt32(buffer, key, value, index) {
@@ -3252,10 +3350,7 @@ function serializeInt32(buffer, key, value, index) {
3252
3350
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3253
3351
  index = index + numberOfWrittenBytes;
3254
3352
  buffer[index++] = 0;
3255
- buffer[index++] = value & 0xff;
3256
- buffer[index++] = (value >> 8) & 0xff;
3257
- buffer[index++] = (value >> 16) & 0xff;
3258
- buffer[index++] = (value >> 24) & 0xff;
3353
+ index += NumberUtils.setInt32LE(buffer, index, value);
3259
3354
  return index;
3260
3355
  }
3261
3356
  function serializeDouble(buffer, key, value, index) {
@@ -3263,9 +3358,7 @@ function serializeDouble(buffer, key, value, index) {
3263
3358
  const numberOfWrittenBytes = ByteUtils.encodeUTF8Into(buffer, key, index);
3264
3359
  index = index + numberOfWrittenBytes;
3265
3360
  buffer[index++] = 0;
3266
- NUMBER_SPACE.setFloat64(0, value.value, true);
3267
- buffer.set(EIGHT_BYTE_VIEW_ON_NUMBER, index);
3268
- index = index + 8;
3361
+ index += NumberUtils.setFloat64LE(buffer, index, value.value);
3269
3362
  return index;
3270
3363
  }
3271
3364
  function serializeFunction(buffer, key, value, index) {
@@ -3275,10 +3368,7 @@ function serializeFunction(buffer, key, value, index) {
3275
3368
  buffer[index++] = 0;
3276
3369
  const functionString = value.toString();
3277
3370
  const size = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3278
- buffer[index] = size & 0xff;
3279
- buffer[index + 1] = (size >> 8) & 0xff;
3280
- buffer[index + 2] = (size >> 16) & 0xff;
3281
- buffer[index + 3] = (size >> 24) & 0xff;
3371
+ NumberUtils.setInt32LE(buffer, index, size);
3282
3372
  index = index + 4 + size - 1;
3283
3373
  buffer[index++] = 0;
3284
3374
  return index;
@@ -3293,19 +3383,13 @@ function serializeCode(buffer, key, value, index, checkKeys = false, depth = 0,
3293
3383
  const functionString = value.code;
3294
3384
  index = index + 4;
3295
3385
  const codeSize = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3296
- buffer[index] = codeSize & 0xff;
3297
- buffer[index + 1] = (codeSize >> 8) & 0xff;
3298
- buffer[index + 2] = (codeSize >> 16) & 0xff;
3299
- buffer[index + 3] = (codeSize >> 24) & 0xff;
3386
+ NumberUtils.setInt32LE(buffer, index, codeSize);
3300
3387
  buffer[index + 4 + codeSize - 1] = 0;
3301
3388
  index = index + codeSize + 4;
3302
3389
  const endIndex = serializeInto(buffer, value.scope, checkKeys, index, depth + 1, serializeFunctions, ignoreUndefined, path);
3303
3390
  index = endIndex - 1;
3304
3391
  const totalSize = endIndex - startIndex;
3305
- buffer[startIndex++] = totalSize & 0xff;
3306
- buffer[startIndex++] = (totalSize >> 8) & 0xff;
3307
- buffer[startIndex++] = (totalSize >> 16) & 0xff;
3308
- buffer[startIndex++] = (totalSize >> 24) & 0xff;
3392
+ startIndex += NumberUtils.setInt32LE(buffer, startIndex, totalSize);
3309
3393
  buffer[index++] = 0;
3310
3394
  }
3311
3395
  else {
@@ -3315,10 +3399,7 @@ function serializeCode(buffer, key, value, index, checkKeys = false, depth = 0,
3315
3399
  buffer[index++] = 0;
3316
3400
  const functionString = value.code.toString();
3317
3401
  const size = ByteUtils.encodeUTF8Into(buffer, functionString, index + 4) + 1;
3318
- buffer[index] = size & 0xff;
3319
- buffer[index + 1] = (size >> 8) & 0xff;
3320
- buffer[index + 2] = (size >> 16) & 0xff;
3321
- buffer[index + 3] = (size >> 24) & 0xff;
3402
+ NumberUtils.setInt32LE(buffer, index, size);
3322
3403
  index = index + 4 + size - 1;
3323
3404
  buffer[index++] = 0;
3324
3405
  }
@@ -3333,19 +3414,19 @@ function serializeBinary(buffer, key, value, index) {
3333
3414
  let size = value.position;
3334
3415
  if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY)
3335
3416
  size = size + 4;
3336
- buffer[index++] = size & 0xff;
3337
- buffer[index++] = (size >> 8) & 0xff;
3338
- buffer[index++] = (size >> 16) & 0xff;
3339
- buffer[index++] = (size >> 24) & 0xff;
3417
+ index += NumberUtils.setInt32LE(buffer, index, size);
3340
3418
  buffer[index++] = value.sub_type;
3341
3419
  if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {
3342
3420
  size = size - 4;
3343
- buffer[index++] = size & 0xff;
3344
- buffer[index++] = (size >> 8) & 0xff;
3345
- buffer[index++] = (size >> 16) & 0xff;
3346
- buffer[index++] = (size >> 24) & 0xff;
3421
+ index += NumberUtils.setInt32LE(buffer, index, size);
3422
+ }
3423
+ if (size <= 16) {
3424
+ for (let i = 0; i < size; i++)
3425
+ buffer[index + i] = data[i];
3426
+ }
3427
+ else {
3428
+ buffer.set(data, index);
3347
3429
  }
3348
- buffer.set(data, index);
3349
3430
  index = index + value.position;
3350
3431
  return index;
3351
3432
  }
@@ -3355,12 +3436,9 @@ function serializeSymbol(buffer, key, value, index) {
3355
3436
  index = index + numberOfWrittenBytes;
3356
3437
  buffer[index++] = 0;
3357
3438
  const size = ByteUtils.encodeUTF8Into(buffer, value.value, index + 4) + 1;
3358
- buffer[index] = size & 0xff;
3359
- buffer[index + 1] = (size >> 8) & 0xff;
3360
- buffer[index + 2] = (size >> 16) & 0xff;
3361
- buffer[index + 3] = (size >> 24) & 0xff;
3439
+ NumberUtils.setInt32LE(buffer, index, size);
3362
3440
  index = index + 4 + size - 1;
3363
- buffer[index++] = 0x00;
3441
+ buffer[index++] = 0;
3364
3442
  return index;
3365
3443
  }
3366
3444
  function serializeDBRef(buffer, key, value, index, depth, serializeFunctions, path) {
@@ -3379,10 +3457,7 @@ function serializeDBRef(buffer, key, value, index, depth, serializeFunctions, pa
3379
3457
  output = Object.assign(output, value.fields);
3380
3458
  const endIndex = serializeInto(buffer, output, false, index, depth + 1, serializeFunctions, true, path);
3381
3459
  const size = endIndex - startIndex;
3382
- buffer[startIndex++] = size & 0xff;
3383
- buffer[startIndex++] = (size >> 8) & 0xff;
3384
- buffer[startIndex++] = (size >> 16) & 0xff;
3385
- buffer[startIndex++] = (size >> 24) & 0xff;
3460
+ startIndex += NumberUtils.setInt32LE(buffer, index, size);
3386
3461
  return endIndex;
3387
3462
  }
3388
3463
  function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializeFunctions, ignoreUndefined, path) {
@@ -3518,7 +3593,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3518
3593
  if ('$' === key[0]) {
3519
3594
  throw new BSONError('key ' + key + " must not start with '$'");
3520
3595
  }
3521
- else if (~key.indexOf('.')) {
3596
+ else if (key.includes('.')) {
3522
3597
  throw new BSONError('key ' + key + " must not contain '.'");
3523
3598
  }
3524
3599
  }
@@ -3616,7 +3691,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3616
3691
  if ('$' === key[0]) {
3617
3692
  throw new BSONError('key ' + key + " must not start with '$'");
3618
3693
  }
3619
- else if (~key.indexOf('.')) {
3694
+ else if (key.includes('.')) {
3620
3695
  throw new BSONError('key ' + key + " must not contain '.'");
3621
3696
  }
3622
3697
  }
@@ -3700,10 +3775,7 @@ function serializeInto(buffer, object, checkKeys, startingIndex, depth, serializ
3700
3775
  path.delete(object);
3701
3776
  buffer[index++] = 0x00;
3702
3777
  const size = index - startingIndex;
3703
- buffer[startingIndex++] = size & 0xff;
3704
- buffer[startingIndex++] = (size >> 8) & 0xff;
3705
- buffer[startingIndex++] = (size >> 16) & 0xff;
3706
- buffer[startingIndex++] = (size >> 24) & 0xff;
3778
+ startingIndex += NumberUtils.setInt32LE(buffer, startingIndex, size);
3707
3779
  return index;
3708
3780
  }
3709
3781
 
@@ -4033,7 +4105,7 @@ function serialize(object, options = {}) {
4033
4105
  buffer = ByteUtils.allocate(minInternalBufferSize);
4034
4106
  }
4035
4107
  const serializationIndex = serializeInto(buffer, object, checkKeys, 0, 0, serializeFunctions, ignoreUndefined, null);
4036
- const finishedBuffer = ByteUtils.allocate(serializationIndex);
4108
+ const finishedBuffer = ByteUtils.allocateUnsafe(serializationIndex);
4037
4109
  finishedBuffer.set(buffer.subarray(0, serializationIndex), 0);
4038
4110
  return finishedBuffer;
4039
4111
  }
@@ -4060,10 +4132,7 @@ function deserializeStream(data, startIndex, numberOfDocuments, documents, docSt
4060
4132
  const bufferData = ByteUtils.toLocalBufferType(data);
4061
4133
  let index = startIndex;
4062
4134
  for (let i = 0; i < numberOfDocuments; i++) {
4063
- const size = bufferData[index] |
4064
- (bufferData[index + 1] << 8) |
4065
- (bufferData[index + 2] << 16) |
4066
- (bufferData[index + 3] << 24);
4135
+ const size = NumberUtils.getInt32LE(bufferData, index);
4067
4136
  internalOptions.index = index;
4068
4137
  documents[docStartIndex + i] = internalDeserialize(bufferData, internalOptions);
4069
4138
  index = index + size;